home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Applications / NIH Image 1.60 / 1.60 Source / File2.p < prev    next >
Encoding:
Text File  |  1996-03-01  |  72.6 KB  |  2,730 lines  |  [TEXT/PJMM]

  1. unit File2;
  2.  
  3. {Routines used by NIH Image for printing plus a few additional File Menu routines.}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources,
  10.         Errors, Palettes, Printing, StandardFile, Folders, TextUtils, Dialogs, Files, Finder, Script,
  11.         globals, Utilities, Graphics, Lut;
  12.  
  13.  
  14.     procedure GetInfo;
  15.     procedure DoPageSetup;
  16.     procedure Print (ShowDialog: boolean);
  17.     procedure SetHalftone;
  18.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  19.     procedure TypeMismatch (fname: str255);
  20.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  21.     function GetTextFile (var name: str255; var RefNum: integer): boolean;
  22.     procedure InitTextInput (name: str255; RefNum: integer);
  23.     procedure GetLineFromText (var rLine: RealLine; var count: integer);
  24.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  25.     procedure PlotXYZ;
  26.     procedure SaveSettings;
  27.     procedure ExportAsText (fname: str255; RefNum: integer);
  28.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  29.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  30.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean;
  31.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  32.     procedure GetTiffColorMap (f: integer);
  33.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  34.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  35.     function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer;
  36.     procedure SaveLUT (fname: str255; RefNum: integer);
  37.     procedure SaveColorTable (fname: str255; RefNum: integer);
  38.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  39.     procedure SaveOutline (fname: str255; RefNum: integer);
  40.     procedure OpenOutline (fname: str255; RefNum: integer);
  41.     function CheckIO (err: OSerr): integer;
  42.     function GetTIFFParameters (name: str255; RefNum: integer; var HasColorMap: boolean): boolean;
  43.     procedure GetXUnits (UnitsKind: UnitsType);
  44.     procedure GetUnitsKInd (var UnitsKind: UnitsType; var UnitsPerCM: extended);
  45.     procedure Swap2Bytes (var i: integer);
  46.     procedure Swap4Bytes (var i: LongInt);
  47.  
  48.  
  49. implementation
  50.  
  51.     var
  52.         gstr: str255;
  53.  
  54.  
  55. {$PUSH}
  56. {$D-}
  57.  
  58.     procedure PrintErrCheck;
  59.         var
  60.             err: integer;
  61.             ticks: LongInt;
  62.     begin
  63.         err := PrError;
  64.         if err < 0 then
  65.             beep;
  66.     end;
  67.  
  68.  
  69.     procedure DoPageSetup;
  70.         var
  71.             result: boolean;
  72.     begin
  73.         PrOpen;
  74.         if PrintRecord = nil then begin
  75.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  76.                 PrintDefault(PrintRecord);
  77.             end;
  78.         if PrError = NoErr then begin
  79.                 result := PrValidate(PrintRecord);
  80.                 result := PrStlDialog(PrintRecord);
  81.             end;
  82.         PrClose;
  83.     end;
  84.  
  85.  
  86.     procedure PrintHalftone;
  87.         const
  88.             PostScriptBegin = 190;
  89.             PostScriptEnd = 191;
  90.             PostScriptHandle = 192;
  91.             TextIsPostScript = 194;
  92.         var
  93.             HexBufH: handle;
  94.             hloc, vloc, HexCount, iheight, iwidth, hstart, vstart: integer;
  95.             Height, Width, eofStr, angle, freq: str255;
  96.             aLine: LineType;
  97.             HexBuf: packed array[0..4200] of char;
  98.             err: OSErr;
  99.             table: LookupTable;
  100.  
  101.         procedure PutHEX (byt: integer);
  102.             var
  103.                 i, LowByte, HighByte, tmp: integer;
  104.                 h: char;
  105.         begin
  106.             if not info^.IdentityFunction then
  107.                 byt := table[byt];
  108.             byt := 255 - byt;
  109.             LowByte := byt mod 16;
  110.             byt := byt div 16;
  111.             HighByte := byt mod 16;
  112.             for i := 1 to 2 do begin
  113.                     if i = 1 then
  114.                         tmp := HighByte
  115.                     else
  116.                         tmp := LowByte;
  117.                     case tmp of
  118.                         0: 
  119.                             h := '0';
  120.                         1: 
  121.                             h := '1';
  122.                         2: 
  123.                             h := '2';
  124.                         3: 
  125.                             h := '3';
  126.                         4: 
  127.                             h := '4';
  128.                         5: 
  129.                             h := '5';
  130.                         6: 
  131.                             h := '6';
  132.                         7: 
  133.                             h := '7';
  134.                         8: 
  135.                             h := '8';
  136.                         9: 
  137.                             h := '9';
  138.                         10: 
  139.                             h := 'a';
  140.                         11: 
  141.                             h := 'b';
  142.                         12: 
  143.                             h := 'c';
  144.                         13: 
  145.                             h := 'd';
  146.                         14: 
  147.                             h := 'e';
  148.                         15: 
  149.                             h := 'f';
  150.                     end;
  151.                     hexbuf[HexCount] := h;
  152.                     HexCount := HexCount + 1;
  153.                     if HexCount mod 80 = 0 then begin
  154.                             HexBuf[HexCount] := cr;
  155.                             HexCount := HexCount + 1
  156.                         end;
  157.                 end;
  158.         end;
  159.  
  160.     begin
  161.         with info^ do begin
  162.                 if not IdentityFunction then
  163.                     GetLookupTable(table);
  164.                 MoveTo(-1, -1);
  165.                 LineTo(-1, -1); {Nothing prints without this dummy dot!}
  166.                 PicComment(PostScriptBegin, 0, nil); {See Tech Note #91}
  167.                 PicComment(TextIsPostScript, 0, nil);
  168.                 NumToString(HalftoneFrequency, freq);
  169.                 NumToString(HalftoneAngle, angle);
  170.                 if HalftoneDotFunction then
  171.                     DrawString(concat(freq, ' ', angle, ' {dup mul exch dup mul add 1 exch sub} setscreen'))
  172.                 else
  173.                     DrawString(concat(freq, ' ', angle, ' {pop} setscreen'));
  174.                 DrawString('0 0 translate');
  175.                 with RoiRect do begin
  176.                         iwidth := right - left;
  177.                         if iwidth > MaxLine then
  178.                             iwidth := MaxLine;
  179.                         iheight := bottom - top;
  180.                         hstart := left;
  181.                         vstart := top;
  182.                     end;
  183.                 NumToString(iwidth, width);
  184.                 NumToString(iheight, height);
  185.                 DrawString(concat(width, ' ', height, ' scale'));
  186.                 DrawString(concat('/PicStr ', width, ' string def'));
  187.                 DrawString(concat(width, ' ', height, ' 8 [', width, ' 0 0 ', height, ' 0 0]'));
  188.                 DrawString('{currentfile PicStr readhexstring pop} image');
  189.                 for vloc := vstart to vstart + iheight - 1 do begin
  190.                         GetLine(hstart, vloc, iwidth, aline);
  191.                         HexCount := 0;
  192.                         for hloc := 0 to iwidth - 1 do
  193.                             PutHex(aline[hloc]);
  194.                         HexBuf[HexCount] := cr;
  195.                         HexCount := HexCount + 1;
  196.                         err := PtrToHand(@HexBuf, HexBufH, HexCount);
  197.                         if err <> noErr then
  198.                             exit(PrintHalftone);
  199.                         PicComment(PostScriptHandle, HexCount, HexBufH);
  200.                         DisposeHandle(HexBufH);
  201.                         Show2Values(vloc - vstart, iheight);
  202.                         if CommandPeriod then begin
  203.                                 beep;
  204.                                 eofStr := chr(4);
  205.                                 DrawString(eofStr);
  206.                                 exit(PrintHalftone)
  207.                             end;
  208.                     end;
  209.             end;
  210.     end;
  211.  
  212.  
  213.     procedure PrintTheImage (PageWidth, PageHeight: integer);
  214.         var
  215.             PrintRect: rect;
  216.             Width, Height: integer;
  217.  
  218.         procedure ScaleToFitPage;
  219.             var
  220.                 hscale, vscale, scale: extended;
  221.         begin
  222.             hscale := PageWidth / width;
  223.             vscale := PageHeight / height;
  224.             if hscale <= vscale then
  225.                 scale := hscale
  226.             else
  227.                 scale := vscale;
  228.             width := trunc(scale * width);
  229.             height := trunc(scale * height);
  230.         end;
  231.  
  232.         procedure CenterOnPage;
  233.         begin
  234.             with PrintRect do begin
  235.                     left := 0;
  236.                     top := 0;
  237.                     if width < PageWidth then
  238.                         left := (PageWidth - width) div 2;
  239.                     if height < PageHeight then
  240.                         top := (Pageheight - height) div 2;
  241.                     right := left + width;
  242.                     bottom := top + height;
  243.                 end;
  244.         end;
  245.  
  246.     begin
  247.         if isLaserWriter and (not DriverHalftoning) then
  248.             PrintHalftone
  249.         else
  250.             with info^ do begin
  251.                     LoadLUT(cTable);
  252.                     hlock(handle(osPort^.portPixMap));
  253.                     with RoiRect do begin
  254.                             width := right - left;
  255.                             height := bottom - top;
  256.                         end;
  257.                     if (width > PageWidth) or (height > PageHeight) then
  258.                         ScaleToFitPage;
  259.                     CenterOnPage;
  260.                     if BitAnd(qd.thePort^.portBits.rowBytes, $8000) = $8000 then begin
  261.                {Assume driver understands Color QD}
  262.                             CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPtr(qd.thePort)^.PortPixMap)^^, RoiRect, PrintRect, SrcCopy, nil);
  263.                         end
  264.                     else
  265.                         CopyBits(BitMapHandle(osPort^.portPixMap)^^, qd.thePort^.PortBits, RoiRect, PrintRect, SrcCopy, nil);
  266.                 end;
  267.     end;
  268.  
  269.  
  270.     procedure PrintTextBuffer (PageHeight: integer; var PrintPort: TPPrPort);
  271.         const
  272.             LineInc = 13;
  273.         var
  274.             vloc, i, LineCount, CharCount, LinesPerPage, MaxCount: integer;
  275.             aLine: str255;
  276.     begin
  277.         ClipTextInBuffer := false;
  278.         LinesPerPage := PageHeight div LineInc;
  279.         vloc := LineInc;
  280.         LineCount := 0;
  281.         CharCount := 0;
  282.         TextFont(Monaco);
  283.         TextSize(9);
  284.         if WhatToPrint = PrintText then
  285.             MaxCount := 85
  286.         else
  287.             MaxCount := 255;
  288.         i := 1;
  289.         repeat
  290.             CharCount := 0;
  291.             while (TextBufP^[i] <> cr) and (CharCount < MaxCount) and (i <= TextBufSize) do begin
  292.                     CharCount := CharCount + 1;
  293.                     aLine[CharCount] := TextBufP^[i];
  294.                     i := i + 1;
  295.                 end;
  296.             if TextBufP^[i] = cr then
  297.                 i := i + 1
  298.             else if CharCount = MaxCount then begin
  299.                     while (aLine[CharCount] <> ' ') and (CharCount > (MaxCount - 15)) do begin
  300.                             CharCount := CharCount - 1;
  301.                             i := i - 1;
  302.                         end;
  303.                     if TextBufP^[i] = ' ' then
  304.                         i := i + 1;
  305.                 end;
  306.             aLine[0] := chr(CharCount);
  307.             MoveTo(0, vloc);
  308.             DrawString(aLine);
  309.             vLoc := vLoc + LineInc;
  310.             LineCount := LineCount + 1;
  311.             if LineCount >= LinesPerPage then begin
  312.                     LineCount := 0;
  313.                     if i < TextBufSize then begin
  314.                             PrClosePage(PrintPort);
  315.                             PrintErrCheck;
  316.                             PrOpenPage(PrintPort, nil);
  317.                             vloc := LineInc
  318.                         end;
  319.                 end;
  320.         until i > TextBufSize;
  321.     end;
  322.  
  323.  
  324.     procedure DoPrintText (PageHeight: integer; var PrintPort: TPPrPort);
  325.         var
  326.             ByteCount: LongInt;
  327.     begin
  328.         if TextInfo <> nil then
  329.             with TextInfo^.TextTE^^ do begin
  330.                     ByteCount := TELength;
  331.                     BlockMove(hText^, ptr(TextBufP), ByteCount);
  332.                     TextBufSize := ByteCount;
  333.                     PrintTextBuffer(PageHeight, PrintPort);
  334.                 end;
  335.     end;
  336.  
  337.  
  338.     procedure Print (ShowDialog: boolean);
  339.         var
  340.             err, i, LinesToPrint: Integer;
  341.             tPort: GrafPtr;
  342.             PrintPort: TPPrPort;
  343.             PrintStatusRec: TPrStatus;
  344.             prect: rect;
  345.             result: boolean;
  346.     begin
  347.         if WhatToPrint = PrintImage then
  348.             SelectAll(false);
  349.         if (WhatToPrint = PrintImage) or (WhatToPrint = PrintSelection) then begin
  350.                 if OpPending then
  351.                     KillRoi;
  352.                 with info^.RoiRect do
  353.                     LinesToPrint := bottom - top;
  354.                 if not DriverHalftoning then begin
  355.                         DrawLabels('Line:', 'Total:', '');
  356.                         Show2Values(0, LinesToPrint);
  357.                     end;
  358.             end;
  359.         GetPort(tPort);
  360.         PrOpen;
  361.         if PrintRecord = nil then begin
  362.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  363.                 PrintDefault(PrintRecord);
  364.             end;
  365.         if PrError = NoErr then begin
  366.                 InitCursor;
  367.                 result := PrValidate(PrintRecord);
  368.                 isLaserWriter := BSR(PrintRecord^^.prStl.wDev, 8) = 3;
  369.                 prect := PrintRecord^^.prInfo.rPage;
  370.                 if ShowDialog then
  371.                     result := PrJobDialog(PrintRecord)
  372.                 else
  373.                     result := true;
  374.                 if not DriverHalftoning then
  375.                     ShowMessage(CmdPeriodToStop);
  376.                 ShowWatch;
  377.                 if result then
  378.                     for i := 1 to PrintRecord^^.PrJob.icopies do begin
  379.                             PrintPort := PrOpenDoc(PrintRecord, nil, nil);
  380.                             PrintErrCheck;
  381.                             Printing := true;
  382.                             PrOpenPage(PrintPort, nil);
  383.                             if PrError = NoErr then
  384.                                 case WhatToPrint of
  385.                                     PrintImage, PrintSelection: 
  386.                                         PrintTheImage(prect.right, prect.bottom);
  387.                                     PrintMeasurements:  begin
  388.                                             CopyResultsToBuffer(1, mCount, true);
  389.                                             PrintTextBuffer(prect.Bottom, PrintPort);
  390.                                             UnsavedResults := false;
  391.                                         end;
  392.                                     PrintPlot: 
  393.                                         DrawPlot;
  394.                                     PrintHistogram: 
  395.                                         DrawHistogram;
  396.                                     PrintText: 
  397.                                         DoPrintText(prect.Bottom, PrintPort);
  398.                                 end;
  399.                             Printing := false;
  400.                             PrClosePage(PrintPort);
  401.                             PrintErrCheck;
  402.                             PrCloseDoc(PrintPort);
  403.                             PrintErrCheck;
  404.                             if PrintRecord^^.prJob.bJDocLoop = bSpoolLoop then
  405.                                 PrPicFile(PrintRecord, nil, nil, nil, PrintStatusRec);
  406.                         end;
  407.             end;
  408.         PrClose;
  409.         SetPort(tPort);
  410.         if WhatToPrint = PrintImage then
  411.             KillRoi;
  412.         ShowMessage(' ');
  413.     end;
  414.  
  415.  
  416.     procedure SetHalftone;
  417.         const
  418.             FrequencyID = 8;
  419.             AngleID = 10;
  420.             DotID = 4;
  421.             LineID = 5;
  422.             CustomID = 13;
  423.         var
  424.             mylog: DialogPtr;
  425.             item, i, ignore, SaveFrequency, SaveAngle: integer;
  426.             SaveFunction, SaveCustom: boolean;
  427.             str: str255;
  428.     begin
  429.         SaveFrequency := HalftoneFrequency;
  430.         SaveAngle := HalftoneAngle;
  431.         SaveFunction := HalftoneDotFunction;
  432.         SaveCustom := DriverHalftoning;
  433.         mylog := GetNewDialog(30, nil, pointer(-1));
  434.         SetDNum(MyLog, FrequencyID, HalftoneFrequency);
  435.         SelectdialogItemText(MyLog, FrequencyID, 0, 32767);
  436.         SetDNum(MyLog, AngleID, HalftoneAngle);
  437.         SetDlogItem(mylog, CustomID, ord(not DriverHalftoning));
  438.         OutlineButton(MyLog, ok, 16);
  439.         if HalftoneDotFunction then
  440.             SetDlogItem(mylog, DotID, 1)
  441.         else
  442.             SetDlogItem(mylog, LineID, 1);
  443.         repeat
  444.             ModalDialog(nil, item);
  445.             if item = FrequencyID then begin
  446.                     HalftoneFrequency := GetDNum(MyLog, FrequencyID);
  447.                     DriverHalftoning := false;
  448.                     SetDlogItem(mylog, CustomID, ord(not DriverHalftoning));
  449.                 end;
  450.             if item = AngleID then begin
  451.                     HalftoneAngle := GetDNum(MyLog, AngleID);
  452.                     if (HalftoneAngle < 0) or (HalftoneAngle > 180) then begin
  453.                             beep;
  454.                             HalftoneAngle := SaveAngle;
  455.                         end;
  456.                     DriverHalftoning := false;
  457.                     SetDlogItem(mylog, CustomID, ord(not DriverHalftoning));
  458.                 end;
  459.             if (item >= DotID) and (item <= LineID) then begin
  460.                     for i := DotID to LineID do
  461.                         SetDlogItem(mylog, i, 0);
  462.                     SetDlogItem(mylog, item, 1);
  463.                     HalftoneDotFunction := item = DotID;
  464.                     DriverHalftoning := false;
  465.                     SetDlogItem(mylog, CustomID, ord(not DriverHalftoning));
  466.                 end;
  467.             if item = CustomID then begin
  468.                     DriverHalftoning := not DriverHalftoning;
  469.                     SetDlogItem(mylog, CustomID, ord(not DriverHalftoning));
  470.                 end;
  471.         until (item = ok) or (item = cancel);
  472.         DisposeDialog(mylog);
  473.         if item = cancel then begin
  474.                 HalftoneFrequency := SaveFrequency;
  475.                 HalftoneAngle := SaveAngle;
  476.                 HalftoneDotFunction := SaveFunction;
  477.                 DriverHalftoning := SaveCustom;
  478.             end;
  479.     end;
  480.  
  481.  
  482. {$POP}
  483.  
  484.     procedure GetFileInfo (name: str255; vnum: integer; var DateCreated, LastModified: str255);
  485.         var
  486.             FileParmBlock: CInfoPBRec;
  487.             theErr: OSErr;
  488.             DateVar, TimeVar: str255;
  489.             Secs: LongInt;
  490.     begin
  491.         DateCreated := '';
  492.             with FileParmBlock do begin
  493.                     ioCompletion := nil;
  494.                     ioNamePtr := @name;
  495.                     ioVRefNum := vnum;
  496.                     ioFVersNum := 0;
  497.                     ioFDirIndex := 0;
  498.                     theErr := PBGetCatInfoSync(@FileParmBlock); {ppc-bug}
  499.                     if theErr = NoErr then begin
  500.                             Secs := ioFlCrDat;
  501.                             IUDateString(Secs, abbrevDate, DateVar);
  502.                             IUTimeString(Secs, true, TimeVar);
  503.                             DateCreated := concat(DateVar, '  ', TimeVar);
  504.                             Secs := ioFlMDDat;
  505.                             IUDateString(Secs, abbrevDate, DateVar);
  506.                             IUTimeString(Secs, true, TimeVar);
  507.                             LastModified := concat(DateVar, '  ', TimeVar);
  508.                         end;
  509.                 end;
  510.     end;
  511.  
  512.  
  513.     procedure GetVolumnInfo (vnum: integer; var VolumnName: str255; var FreeSpace: LongInt);
  514.         var
  515.             theErr: OSErr;
  516.             str: str255;
  517.             VolParmBlock: ParamBlockRec;
  518.     begin
  519.         VolumnName := '';
  520.             with VolParmBlock do begin
  521.                     str := '';
  522.                     ioVRefNum := vnum;
  523.                     ioNamePtr := @str;
  524.                     ioCompletion := nil;
  525.                     ioVolIndex := -1;
  526.                     theErr := PBGetVInfoSync(@VolParmBlock); {ppc-bug}
  527.                     VolumnName := ioNamePtr^;
  528.                     FreeSpace := ioVAlBlkSiz * ioVFrBlk;
  529.                 end;
  530.     end;
  531.  
  532.  
  533.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  534.         var
  535.             err: OSErr;
  536.             f: integer;
  537.             VolumnName: str255;
  538.             FreeSpace, ExistingFileSize, NeededSize: LongInt;
  539.     begin
  540.         with info^ do begin
  541.                 ExistingFileSize := 0;
  542.                 RoomForFile := true;
  543.                 err := fsopen(fname, RefNum, f);
  544.                 if err = 0 then begin
  545.                         err := GetEOF(f, ExistingFileSize);
  546.                         err := fsClose(f);
  547.                     end;
  548.                 if ExistingFileSize <> 0 then begin
  549.                         if SavingSelection then begin
  550.                                 NeededSize := sLines;
  551.                                 NeededSize := NeededSize * sPixelsPerLine
  552.                             end
  553.                         else
  554.                             NeededSize := ImageSize;
  555.                         if StackInfo <> nil then
  556.                             with StackInfo^ do
  557.                                 NeededSize := NeededSize * nSlices + nSlices * SizeOf(StackIFDType);
  558.                         GetVolumnInfo(RefNum, VolumnName, FreeSpace);
  559.                         if (NeededSize - ExistingFileSize + 8192) > FreeSpace then begin
  560.                                 PutError('There is not enough free space on this disk to save this image.');
  561.                                 RoomForFile := false;
  562.                             end;
  563.                     end;
  564.             end;
  565.     end;
  566.  
  567.  
  568.     procedure GetInfo;
  569.         var
  570.             name, str, DateCreated, LastModified, VolumnName, str2: str255;
  571.             hloc, vloc, InfoWidth, InfoHeight: integer;
  572.             SaveRoiShowing: boolean;
  573.             FreeSpace, DataSize: LongInt;
  574.             SaveForeIndex, SaveBackIndex: integer;
  575.             ImageInfo, InfoWindowInfo: InfoPtr;
  576.             x1, y1, x2, y2, ulength, clength: extended;
  577.             SaveGDevice: GDHandle;
  578.  
  579.         procedure NewLine;
  580.         begin
  581.             vloc := vloc + 13;
  582.             MoveTo(hloc, vloc);
  583.         end;
  584.  
  585.         procedure NewParagraph;
  586.         begin
  587.             vloc := vloc + 18;
  588.             MoveTo(hloc, vloc);
  589.         end;
  590.  
  591.     begin
  592.         InfoWidth := 260;
  593.         InfoHeight := 260;
  594.         with info^ do begin
  595.                 if RoiShowing then
  596.                     InfoHeight := InfoHeight + 50;
  597.                 if RoiShowing and (RoiType = LineRoi) then
  598.                     InfoHeight := InfoHeight + 20;
  599.                 if vref <> 0 then
  600.                     InfoHeight := InfoHeight + 60;
  601.                 name := concat('Info About ', title);
  602.                 SaveRoiShowing := RoiShowing;
  603.             end;
  604.         SaveForeIndex := ForegroundIndex;
  605.         SaveBackIndex := BackgroundIndex;
  606.         SetForegroundColor(BlackIndex);
  607.         SetBackgroundColor(WhiteIndex);
  608.         ImageInfo := info;
  609.         if NewPicWindow(name, InfoWidth, InfoHeight) then
  610.             with ImageInfo^ do begin
  611.                     InfoWindowInfo := Info;
  612.                     SaveGDevice := GetGDevice;
  613.                     SetGDevice(osGDevice);
  614.                     SetPort(GrafPtr(info^.osPort));
  615.                     TextFont(Geneva);
  616.                     TextSize(9);
  617.                     hloc := 15;
  618.                     vloc := 10;
  619.                     NewLine;
  620.                     DrawBString('Name: ');
  621.                     DrawString(title);
  622.                     NewParagraph;
  623.                     DrawBString('Width: ');
  624.                     DrawXDimension(PixelsPerLine, 0);
  625.                     NewLine;
  626.                     DrawBString('Height: ');
  627.                     DrawYDimension(nlines, 0);
  628.                     if StackInfo <> nil then begin
  629.                             NewLine;
  630.                             DrawBString('Depth: ');
  631.                             DrawLong(StackInfo^.nSlices);
  632.                         end;
  633.                     NewLine;
  634.                     DrawBString('Size: ');
  635.                     if StackInfo <> nil then
  636.                         DataSize := PixMapSize * StackInfo^.nSlices
  637.                     else if DataH <> nil then
  638.                         DataSize := PixMapSize + PixMapSize * SizeOf(real)
  639.                     else
  640.                         DataSize := PixMapSize;
  641.                     DrawLong((DataSize + 511) div 1024);
  642.                     DrawString('K');
  643.                     NewParagraph;
  644.                     GetFileInfo(title, vref, DateCreated, LastModified); {DateCreated:='';}
  645.                     if DateCreated <> '' then begin
  646.                             DrawBString('Creation Date: ');
  647.                             DrawString(DateCreated);
  648.                             NewLine;
  649.                             DrawBString('Last Modified: ');
  650.                             DrawString(LastModified);
  651.                             NewLine;
  652.                         end;
  653.                     if fileVersion > 0 then begin
  654.                             DrawBString('Version: ');
  655.                             DrawString('Created by NIH Image ');
  656.                             DrawReal(fileVersion / 100.0, 1, 2);
  657.                             NewParagraph;
  658.                         end;
  659.                     DrawBString('Type: ');
  660.                     if StackInfo <> nil then case StackInfo^.StackType of
  661.                         VolumeStack, MovieStack:
  662.                             str := concat('Stack (', long2str(StackInfo^.nSlices), '  slices)');
  663.                         rgbStack:
  664.                             str := 'RGB color stack';
  665.                         else
  666.                         ;
  667.                     end else begin
  668.                             case PictureType of
  669.                                 NewPicture: 
  670.                                     str := 'New';
  671.                                 Normal: 
  672.                                     str := 'Normal';
  673.                                 PictFile: 
  674.                                     str := 'PICT';
  675.                                 TiffFile: 
  676.                                     str := 'TIFF';
  677.                                 Leftover: 
  678.                                     str := 'Left Over';
  679.                                 Imported:  begin
  680.                                         if DataType = EightBits then
  681.                                             str := 'Imported 8-bit image'
  682.                                         else
  683.                                             str := 'Imported 16-bit image';
  684.                                     end;
  685.                                 FrameGrabberType: 
  686.                                     str := 'Camera';
  687.                                 BlankField: 
  688.                                     str := 'Blank Field';
  689.                                 otherwise
  690.                                     ;
  691.                             end;
  692.                             if BinaryPic then
  693.                                 str := concat(str, ' (Binary)');
  694.                         end;
  695.                     DrawString(str);
  696.                     if StackInfo <> nil then
  697.                         with StackInfo^ do
  698.                             if SliceSpacing <> 0.0 then begin
  699.                                     NewLine;
  700.                                     DrawBString('Slice Spacing: ');
  701.                                     if SpatiallyCalibrated then
  702.                                         DrawString(StringOf(SliceSpacing / xScale:1:2, ' ', xunit, ' (', SliceSpacing:1:2, ' pixels)'))
  703.                                     else
  704.                                         DrawString(StringOf(SliceSpacing:1:2, ' pixels'));
  705.                                 end;
  706.                     NewLine;
  707.                     DrawBString('Lookup Table: ');
  708.                     case LutMode of
  709.                         PseudoColor: 
  710.                             str := concat('Pseudocolor (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  711.                         GrayScale: 
  712.                             str := concat('Grayscale (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  713.                         ColorLut: 
  714.                             str := 'Color';
  715.                         CustomGrayscale: 
  716.                             str := 'Custom Grayscale';
  717.                         otherwise
  718.                     end;
  719.                     DrawString(str);
  720.                     NewLine;
  721.                     DrawBString('Magnification: ');
  722.                     if ScaleToFitWindow then begin
  723.                             DrawReal(magnification, 1, 2);
  724.                             DrawString(' (Scale to Window Mode)')
  725.                         end
  726.                     else begin
  727.                             DrawReal(magnification, 1, 0);
  728.                             DrawString(':1')
  729.                         end;
  730.                     NewLine;
  731.                     DrawBString('Scale: ');
  732.                     if SpatiallyCalibrated then begin
  733.                             DrawReal(xScale, 1, 3);
  734.                             DrawString(' pixels per ');
  735.                             DrawString(xUnit);
  736.                             if PixelAspectRatio <> 1.0 then begin
  737.                                     NewLine;
  738.                                     DrawBString('Pixel Aspect Ratio: ');
  739.                                     DrawReal(PixelAspectRatio, 1, 4);
  740.                                 end;
  741.                         end
  742.                     else
  743.                         DrawString('None');
  744.                     if fit <> uncalibrated then begin
  745.                             NewLine;
  746.                             DrawBString('Unit of Measure: ');
  747.                             if UnitOfMEasure = '' then
  748.                                 DrawString('None')
  749.                             else
  750.                                 DrawString(UnitOfMeasure)
  751.                         end;
  752.                     NewParagraph;
  753.                     DrawBString('Free RAM: ');
  754.                     DrawLong(FreeMem div 1024);
  755.                     DrawString('K');
  756.                     NewLine;
  757.                     DrawBString('Largest Free Block: ');
  758.                     DrawLong(MaxBlock div 1024);
  759.                     DrawString('K');
  760.                     if FrameGrabber <> NoFrameGrabber then begin
  761.                             NewLine;
  762.                             DrawBString('Frame Grabber: ');
  763.                             case FrameGrabber of
  764.                                 QuickCapture:  begin
  765.                                         if fgWidth = 768 then
  766.                                             DrawString('50Hz')
  767.                                         else
  768.                                             DrawString('60Hz');
  769.                                         DrawString(' Data Translation QuickCapture');
  770.                                     end;
  771.                                 ScionLG3:  begin
  772.                                         if fgWidth = 768 then
  773.                                             DrawString('50Hz')
  774.                                         else
  775.                                             DrawString('60Hz');
  776.                                         DrawString(' Scion LG-3 (');
  777.                                         DrawLong(MaxLG3Frames div 2);
  778.                                         DrawString(' MB)');
  779.                                     end;
  780.                                 ScionAG5:  begin
  781.                                     if fgWidth = 768 then
  782.                                         DrawString('50Hz')
  783.                                     else
  784.                                         DrawString('60Hz');
  785.                                     DrawString(' Scion AG-5');
  786.                                 end;
  787.                                 ScionVG5f:  begin
  788.                                     if fgWidth = 768 then
  789.                                         DrawString('50Hz')
  790.                                     else
  791.                                         DrawString('60Hz');
  792.                                     DrawString(' Scion VG-5');
  793.                                 end
  794.                                 QTvdig:
  795.                                     DrawString('QuickTime Video Digitizer');
  796.                             end;
  797.                         end;
  798.                     NewParagraph;
  799.                     if RoiType <> NoRoi then begin
  800.                             DrawBString('Selection Type: ');
  801.                             case RoiType of
  802.                                 PolygonRoi: 
  803.                                     DrawString('Polygon');
  804.                                 FreehandRoi: 
  805.                                     DrawString('Freehand');
  806.                                 RectRoi: 
  807.                                     DrawString('Rectangle');
  808.                                 OvalRoi: 
  809.                                     DrawString('Oval');
  810.                                 LineRoi: 
  811.                                     DrawString('Straight Line');
  812.                                 FreeLineRoi: 
  813.                                     DrawString('Freehand Line');
  814.                                 SegLineRoi: 
  815.                                     DrawString('Segmented Line');
  816.                                 TracedRoi:
  817.                                     DrawString('Traced');
  818.                             end;
  819.                             NewLine;
  820.                             case RoiType of
  821.                                 PolygonRoi, FreehandRoi, RectRoi, OvalRoi, TracedRoi: 
  822.                                     with RoiRect do begin
  823.                                             DrawBString('    Left: ');
  824.                                             DrawXDimension(left, 0);
  825.                                             NewLine;
  826.                                             DrawBString('    Top: ');
  827.                                             if InvertYCoordinates then
  828.                                                 DrawYDimension(PicRect.bottom - top - 1, 0)
  829.                                             else
  830.                                                 DrawYDimension(top, 0);
  831.                                             NewLine;
  832.                                             DrawBString('    Width: ');
  833.                                             DrawXDimension(right - left, 0);
  834.                                             NewLine;
  835.                                             DrawBString('    Height: ');
  836.                                             DrawYDimension(bottom - top, 0);
  837.                                         end;
  838.                                 LineRoi:  begin
  839.                                         info := ImageInfo;
  840.                                         GetLengthOrPerimeter(ulength, clength);
  841.                                         GetLoi(x1, y1, x2, y2);
  842.                                         Info := InfoWindowInfo;
  843.                                         DrawBString('    Length: ');
  844.                                         if SpatiallyCalibrated then begin
  845.                                                 DrawReal(cLength, 1, 2);
  846.                                                 DrawString(xUnit);
  847.                                             end
  848.                                         else
  849.                                             DrawReal(uLength, 1, 2);
  850.                                         NewLine;
  851.                                         DrawBString('    Angle: ');
  852.                                         DrawReal(LAngle, 1, 2);
  853.                                         DrawString('°');
  854.                                         NewLine;
  855.                                         DrawBString('    X1: ');
  856.                                         DrawXDimension(x1, 2);
  857.                                         NewLine;
  858.                                         DrawBString('    Y1: ');
  859.                                         if InvertYCoordinates then
  860.                                             DrawYDimension(PicRect.bottom - y1 - 1, 2)
  861.                                         else
  862.                                             DrawYDimension(y1, 2);
  863.                                         NewLine;
  864.                                         DrawBString('    X2: ');
  865.                                         DrawXDimension(x2, 2);
  866.                                         NewLine;
  867.                                         DrawBString('    Y2: ');
  868.                                         if InvertYCoordinates then
  869.                                             DrawYDimension(PicRect.bottom - y2 - 1, 2)
  870.                                         else
  871.                                             DrawYDimension(y2, 2);
  872.                                     end;
  873.                                 FreeLineRoi, SegLineRoi:  begin
  874.                                         info := ImageInfo;
  875.                                         GetLengthOrPerimeter(ulength, clength);
  876.                                         Info := InfoWindowInfo;
  877.                                         DrawBString('    Length: ');
  878.                                         if SpatiallyCalibrated then begin
  879.                                                 DrawReal(cLength, 1, 2);
  880.                                                 DrawString(xUnit);
  881.                                             end
  882.                                         else
  883.                                             DrawReal(uLength, 1, 2);
  884.                                         NewLine;
  885.                                     end;
  886.                                 otherwise
  887.                             end; {case}
  888.                         end
  889.                     else
  890.                         DrawBString('No Selection');
  891.                     SetGDevice(SaveGDevice);
  892.                 end; {with ImageInfo^}
  893.         SetForegroundColor(SaveForeIndex);
  894.         SetBackgroundColor(SaveBackIndex);
  895.     end;
  896.  
  897.  
  898.     function CheckIO (err: OSerr): integer;
  899.         var
  900.             ErrStr, Message: str255;
  901.             ignore: integer;
  902.             SaveGDevice: GDHandle;
  903.     begin
  904.         if err <> 0 then begin
  905.                 case err of
  906.                     -34: Message := 'Disk Full';
  907.                     -35: Message := 'No such volume';
  908.                     -36: Message := 'I/O Error';
  909.                     -39: Message := 'End of file error';
  910.                     -49: Message := 'File in Use';
  911.                     -61: Message := 'Write Permission Error';
  912.                     -120: Message := 'Folder not found'
  913.                     otherwise Message := '';
  914.                 end;
  915.                 SaveGDevice := GetGDevice;
  916.                 SetGDevice(GetMainDevice);
  917.                 NumToString(err, ErrStr);
  918.                 ParamText(Message, ErrStr, '', '');
  919.                 InitCursor;
  920.                 ignore := alert(IOErrorID, nil);
  921.                 SetGDevice(SaveGDevice);
  922.                 AbortMacro;
  923.             end;
  924.         CheckIO := err;
  925.     end;
  926.     
  927.  
  928.  
  929.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  930.         const
  931.             MaxUnPackedSize = 51840;   {Max MacPaint size in bytes=720 lines * 72 bytes/line }
  932.         type
  933.             mpLine = array[1..18] of LongInt;
  934.             mpArrayT = array[1..720] of mpLine;
  935.             mpArrayP = ^mpArrayT;
  936.         var
  937.             i, f, ScanLine, LastLine, LastWord, LastColumn: integer;
  938.             err: osErr;
  939.             srcSize: LongInt;
  940.             srcPtr, dstPtr, src, dst: ptr;
  941.             theBitMap: BitMap;
  942.             mpArray: mpArrayP;
  943.             BlankLine, BlankColumn: boolean;
  944.             frect: rect;
  945.             SaveGDevice: GDHandle;
  946.  
  947.         procedure abort;
  948.         begin
  949.             beep;
  950.             if srcPtr <> nil then
  951.                 DisposePtr(srcPtr);
  952.             if dstPtr <> nil then
  953.                 DisposePtr(dstPtr);
  954.             {exit(OpenMacPaint);} {ppc-bug}
  955.         end;
  956.  
  957.     begin
  958.         OpenMacPaint := false;
  959.         err := fsOpen(fname, vnum, f);
  960.         if CheckIO(err) <> noErr then
  961.             exit(OpenMacPaint);
  962.         err := GetEOF(f, srcSize);
  963.         srcSize := srcSize - 512;
  964.         srcPtr := NewPtr(srcSize);
  965.         if srcPtr = nil then begin
  966.             abort;
  967.             exit(OpenMacPaint);
  968.         end;
  969.         err := SetFPos(f, fsFromStart, 512);
  970.         err := fsRead(f, srcSize, srcPtr);
  971.         if CheckIO(err) <> noErr then
  972.             exit(OpenMacPaint);
  973.         err := fsClose(f);
  974.         dstPtr := NewPtrClear(MaxUnPackedSize);
  975.         if dstPtr = nil then begin
  976.             abort;
  977.             exit(OpenMacPaint);
  978.         end;
  979.         src := srcPtr;
  980.         dst := dstPtr;
  981.         for scanLine := 1 to 720 do
  982.             UnPackBits(src, dst, 72); {bumps both ptrs}
  983.         DisposePtr(srcPtr);
  984.         mpArray := mpArrayP(dstPtr);
  985.         LastLine := 720;
  986.         BlankLine := true;
  987.         repeat
  988.             for i := 1 to 18 do
  989.                 blankLine := BlankLine and (mpArray^[LastLine, i] = 0);
  990.             if BlankLine then
  991.                 LastLine := LastLine - 1;
  992.         until (not BlankLine) or (LastLine = 1);
  993.         LastWord := 18;
  994.         BlankColumn := true;
  995.         repeat
  996.             for i := 1 to LastLine do
  997.                 blankColumn := BlankColumn and (mpArray^[i, LastWord] = 0);
  998.             if BlankColumn then
  999.                 LastWord := LastWord - 1;
  1000.         until (not BlankColumn) or (LastWord = 1);
  1001.         LastColumn := LastWord * 32;
  1002.         LastColumn := LastColumn + 8;
  1003.         if LastColumn > 576 then
  1004.             LastColumn := 576;
  1005.         LastLine := LastLine + 8;
  1006.         if LastLine > 720 then
  1007.             LastLine := 720;
  1008.         SetRect(frect, 0, 0, LastColumn, LastLine);
  1009.         with theBitMap do begin
  1010.                 baseAddr := dstPtr;
  1011.                 rowBytes := 72;
  1012.                 bounds := frect;
  1013.             end;
  1014.         if not NewPicWindow(fname, LastColumn, LastLine) then begin
  1015.             abort;
  1016.             exit(OpenMacPaint);
  1017.         end;
  1018.         SaveGDevice := GetGDevice;
  1019.         SetGDevice(osGDevice);
  1020.         SetForegroundColor(BlackIndex);
  1021.         SetBackgroundColor(WhiteIndex);
  1022.         with info^ do begin
  1023.                 CopyBits(theBitMap, BitMapHandle(osPort^.PortPixMap)^^, frect, frect, SrcCopy, nil);
  1024.                 DisposePtr(dstPtr);
  1025.                 PictureType := imported;
  1026.                 BinaryPic := true;
  1027.                 SetGDevice(SaveGDevice);
  1028.                 if PixMapSize > UndoBufSize then
  1029.                     PutWarning;
  1030.             end;
  1031.         OpenMacPaint := true;
  1032.     end;
  1033.  
  1034.  
  1035.     procedure TypeMismatch (fname: str255);
  1036.     begin
  1037.         PutError(concat('The file "', fname, '" is a different type, and therefore cannot be replaced'));
  1038.     end;
  1039.  
  1040.  
  1041.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  1042.         const
  1043.             MaxFileSize = 53072;   { maximum MacPaint file size. }
  1044.         var
  1045.             TheInfo: FInfo;
  1046.             dstPtr, srcPtr, mpBufPtr: Ptr;
  1047.             i, f, scanLine, err, width, height: integer;
  1048.             dstBuffer: array[1..128] of LongInt;
  1049.             size, dstSize: LongInt;
  1050.             theBitMap: BitMap;
  1051.             mprect, srect, drect: rect;
  1052.  
  1053.         procedure abort;
  1054.         begin
  1055.             beep;
  1056.             if mpBufPtr <> nil then
  1057.                 DisposePtr(mpBufPtr);
  1058.             if f <> -1 then
  1059.                 err := fsclose(f);
  1060.             {exit(SaveAsMacPaint);} {ppc-bug}
  1061.         end;
  1062.  
  1063.     begin
  1064.         f := -1;
  1065.         err := GetFInfo(fname, RefNum, TheInfo);
  1066.         case err of
  1067.             NoErr: 
  1068.                 with TheInfo do begin
  1069.                         if fdType <> 'PNTG' then begin
  1070.                                 TypeMismatch(fname);
  1071.                                 exit(SaveAsMacPaint)
  1072.                             end;
  1073.                     end;
  1074.             FNFerr:  begin
  1075.                     err := create(fname, RefNum, 'MPNT', 'PNTG');
  1076.                     if CheckIO(err) <> 0 then
  1077.                         exit(SaveAsMacPaint);
  1078.                 end;
  1079.             otherwise
  1080.                 if CheckIO(err) <> 0 then
  1081.                     exit(SaveAsMacPaint);
  1082.         end;
  1083.         mpBufPtr := NewPtrClear(MaxFileSize);
  1084.         if mpBufPtr = nil then begin
  1085.             abort;
  1086.             exit(SaveAsMacPaint);
  1087.         end;
  1088.         ShowWatch;
  1089.         SetRect(mprect, 0, 0, 576, 720);
  1090.         with theBitMap do begin
  1091.                 baseAddr := mpBufPtr;
  1092.                 rowBytes := 72;
  1093.                 bounds := mprect;
  1094.             end;
  1095.         with info^ do begin
  1096.                 if roiShowing then
  1097.                     srect := RoiRect
  1098.                 else
  1099.                     srect := PicRect;
  1100.                 with srect do begin
  1101.                         width := right - left;
  1102.                         height := bottom - top;
  1103.                         if width > 576 then
  1104.                             width := 576;
  1105.                         if height > 720 then
  1106.                             height := 720;
  1107.                         right := left + width;
  1108.                         bottom := top + height;
  1109.                     end;
  1110.                 SetRect(drect, 0, 0, width, height);
  1111.                 CopyBits(BitMapHandle(osPort^.PortPixMap)^^, theBitMap, srect, drect, srcCopy, nil);
  1112.             end;
  1113.         err := fsOpen(fname, RefNum, f);
  1114.         if CheckIO(err) <> noErr then begin
  1115.             abort;
  1116.             exit(SaveAsMacPaint);
  1117.         end;
  1118.         for I := 1 to 128 do
  1119.             dstBuffer[I] := 0;
  1120.         Size := 512;
  1121.         err := FSWrite(f, Size, @dstBuffer);
  1122.         if CheckIO(err) <> noErr then begin
  1123.             abort;
  1124.             exit(SaveAsMacPaint);
  1125.         end;
  1126.         srcPtr := theBitMap.baseAddr;
  1127.         for scanLine := 1 to 720 do begin
  1128.                 dstPtr := @dstBuffer; { reset the pointer to bottom }
  1129.                 PackBits(srcPtr, dstPtr, 72); { bumps both ptrs}
  1130.                 dstSize := ord(dstPtr) - ord(@dstBuffer);{calc packed size}
  1131.                 err := fsWrite(f, dstSize, @dstBuffer);
  1132.                 if CheckIO(err) <> noErr then begin
  1133.                     abort;
  1134.                     exit(SaveAsMacPaint);
  1135.                 end;
  1136.             end;
  1137.         err := fsclose(f);
  1138.         DisposePtr(mpBufPtr);
  1139.         if not info^.RoiShowing then
  1140.             info^.changes := false;
  1141.     end;
  1142.  
  1143.  
  1144.     function GetTextFile (var name: str255; var RefNum: integer): boolean;
  1145.         var
  1146.             where: Point;
  1147.             typeList: SFTypeList;
  1148.             reply: SFReply;
  1149.             err: OSErr;
  1150.             pBlock: WDPBRec;
  1151.     begin
  1152.         where.v := 120;
  1153.         where.h := 120;
  1154.         typeList[0] := 'TEXT';
  1155.         SFGetFile(Where, '', nil, 1, @typeList, nil, reply);
  1156.         if reply.good then
  1157.             with reply do begin
  1158.                     name := fname;
  1159.                     RefNum := vRefNum;
  1160.                     GetTextFile := true;
  1161.                 end
  1162.         else
  1163.             GetTextFile := false;
  1164.     end;
  1165.  
  1166.  
  1167.     procedure GetBuffer;
  1168.         var
  1169.             err: OSErr;
  1170.             count, FilePos: LongInt;
  1171.     begin
  1172.         count := MaxTextBufSize;
  1173.         err := fsread(Textf, count, ptr(TextBufP));
  1174.         TextBufSize := count;
  1175.         err := GetFPos(Textf, FilePos);
  1176.         if FilePos = TextFileSize then begin
  1177.                 TextBufSize := TextBufSize + 1;
  1178.                 if TextBufSize > MaxTextBufSize then
  1179.                     TextBufSize := MaxTextBufSize;
  1180.                 TextBufP^[TextBufSize] := eofChr;
  1181.                 err := fsclose(Textf);
  1182.             end;
  1183.         TextIndex := 1;
  1184.     end;
  1185.  
  1186.  
  1187.     function GetByte: char;
  1188.     begin
  1189.         GetByte := TextBufP^[TextIndex];
  1190.         TextIndex := TextIndex + 1;
  1191.         if TextIndex > MaxTextBufSize then
  1192.             GetBuffer;
  1193.     end;
  1194.  
  1195.  
  1196.     function GetNumber: extended;
  1197.         var
  1198.             c: char;
  1199.             str: str255;
  1200.     begin
  1201.         repeat
  1202.             c := GetByte;
  1203.             if c = tab then begin
  1204.                     GetNumber := 0.0; {Assume 0 zero for missing value.}
  1205.                     exit(GetNumber);
  1206.                 end;
  1207.             if (c = cr) or (c = eofChr) then begin
  1208.                     TextEol := true;
  1209.                     TextEof := c = eofChr;
  1210.                     GetNumber := NoValue;
  1211.                     exit(GetNumber);
  1212.                 end;
  1213.         until c in ['0'..'9', '-', '.'];
  1214.         Str := '';
  1215.         while c in ['0'..'9', '+', '-', '.', 'e', 'E'] do begin
  1216.                 Str := concat(str, c);
  1217.                 c := GetByte;
  1218.                 if (c = cr) or (c = eofChr) then begin
  1219.                         TextEol := true;
  1220.                         TextEof := c = eofChr;
  1221.                     end;
  1222.             end;
  1223.         GetNumber := StringToReal(str);
  1224.     end;
  1225.  
  1226.  
  1227.     procedure GetLineFromText (var rLine: RealLine; var count: integer);
  1228.         var
  1229.             n: extended;
  1230.     begin
  1231.         count := 0;
  1232.         if TextEof then
  1233.             exit(GetLineFromText);
  1234.         repeat
  1235.             n := GetNumber;
  1236.             if n <> NoValue then begin
  1237.                     count := count + 1;
  1238.                     rLine[count] := n;
  1239.                 end;
  1240.         until TextEol or (count = MaxLine);
  1241.         TextEol := false;
  1242.     end;
  1243.  
  1244.  
  1245.     procedure InitTextInput (name: str255; RefNum: integer);
  1246.         var
  1247.             err: OSErr;
  1248.     begin
  1249.         err := FSOpen(name, RefNum, Textf);
  1250.         err := GetEof(Textf, TextFileSize);
  1251.         err := SetFPos(Textf, fsFromStart, 0);
  1252.         ShowWatch;
  1253.         if WhatsOnClip = TextOnClip then
  1254.             WhatsOnClip := NothingOnClip;
  1255.         GetBuffer;
  1256.         TextEol := false;
  1257.         TextEof := false;
  1258.     end;
  1259.  
  1260.  
  1261.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  1262.         var
  1263.             nRows, nColumns, count, i, vloc, BlankPixel, nPixelsPerLine: integer;
  1264.             rLine: RealLine;
  1265.             pvalue: extended;
  1266.             min, max, ScaleFactor, DefaultValue, tvalue: extended;
  1267.             err: OSErr;
  1268.             line, BlankLine: LineType;
  1269.             TheInfo: FInfo;
  1270.             noScaling:boolean;
  1271.     begin
  1272.         ImportTextFile := false;
  1273.         err := GetFInfo(name, RefNum, TheInfo);
  1274.         if TheInfo.fdType <> 'TEXT' then begin
  1275.                 PutError('File is not of type ''TEXT''.');
  1276.                 exit(ImportTextFile);
  1277.             end;
  1278.         InitTextInput(name, RefNum);
  1279.         nRows := 0;
  1280.         nColumns := 0;
  1281.         max := -10e-10;
  1282.         min := 10e10;
  1283.         ShowMessage(concat('First pass used to find ', crStr, 'width, height,min, and max.', crStr, crStr, CmdPeriodToStop));
  1284.         DrawLabels('Line:', '', '');
  1285.         while not TextEof do begin
  1286.                 GetLineFromText(rLine, count);
  1287.                 if not (TextEof and (count = 0)) then
  1288.                     nRows := nRows + 1;
  1289.                 if count > nColumns then
  1290.                     nColumns := count;
  1291.                 for i := 1 to count do begin
  1292.                         pvalue := rLine[i];
  1293.                         if pvalue > max then
  1294.                             max := pvalue;
  1295.                         if pvalue < min then
  1296.                             min := pvalue;
  1297.                     end;
  1298.                 if nRows mod 10 = 0 then begin
  1299.                         Show1Value(nRows, NoValue);
  1300.                         ShowAnimatedWatch;
  1301.                         if CommandPeriod then begin
  1302.                                 beep;
  1303.                                 err := fsclose(Textf);
  1304.                                 Exit(ImportTextFile);
  1305.                             end;
  1306.                     end;
  1307.             end;
  1308.         ShowMessage(concat('rows= ', long2str(nRows), crStr, 'columns= ', long2str(ncolumns), crStr, 'min= ', long2str(round(min)), crStr, 'max= ', long2str(round(max))));
  1309.         if nColumns > MaxLine then begin
  1310.                 PutError(concat('More than ',long2str(MaxLine),' pixels per line.'));
  1311.                 Exit(ImportTextFile);
  1312.             end;
  1313.         nPixelsPerLine := nColumns;
  1314.         if NewPicWindow(name, nPixelsPerLine, nrows) then
  1315.             with info^ do begin
  1316.                     if (not ImportAutoScale) and (max > min) then begin
  1317.                             min := ImportMin;
  1318.                             max := ImportMax;
  1319.                         end;
  1320.                     ScaleFactor := 253.0 / (max - min);
  1321.                     InitTextInput(name, RefNum);
  1322.                     vloc := 0;
  1323.                     DefaultValue := 0.0;
  1324.                     if DefaultValue < min then
  1325.                         DefaultValue := min;
  1326.                     if DefaultValue > max then
  1327.                         DefaultValue := max;
  1328.                     BlankPixel := round((DefaultValue - min) * ScaleFactor + 1);
  1329.                     for i := 0 to nColumns - 1 do
  1330.                         BlankLine[i] := BlankPixel;
  1331.                     NoScaling:=not ImportAutoScale and ((min=0) and (max=255));
  1332.                     DrawLabels('Line:', 'Total:', '');
  1333.                     while not TextEof do begin
  1334.                             GetLineFromText(rLine, count);
  1335.                             if not (TextEof and (count = 0)) then begin
  1336.                                     line := BlankLine;
  1337.                                     if ImportAutoScale then     {Map values into the range 1-254}
  1338.                                         for i := 1 to count do
  1339.                                             line[i - 1] := round((rLine[i] - min) * ScaleFactor + 1)
  1340.                                     else
  1341.                                         for i := 1 to count do begin
  1342.                                                 tvalue := rLine[i];
  1343.                                                 if tvalue < min then
  1344.                                                     tvalue := min;
  1345.                                                 if tvalue > max then
  1346.                                                     tvalue := max;
  1347.                                                 if noScaling
  1348.                                                     then line[i - 1]:=round(tvalue)
  1349.                                                     else line[i - 1] := round((tvalue - min) * ScaleFactor + 1);
  1350.                                             end;
  1351.                                     PutLine(0, vloc, PixelsPerLine, line);
  1352.                                     vloc := vloc + 1;
  1353.                                 end;
  1354.                             if vloc mod 10 = 0 then begin
  1355.                                     Show2Values(vloc, nRows);
  1356.                                     ShowAnimatedWatch;
  1357.                                     if CommandPeriod then begin
  1358.                                             beep;
  1359.                                             err := fsclose(Textf);
  1360.                                             Exit(ImportTextFile);
  1361.                                         end;
  1362.                                 end;
  1363.                         end;
  1364.                     if noScaling then
  1365.                         ImportCalibrate:=false
  1366.                     else begin
  1367.                         fit := StraightLine;
  1368.                         nCoefficients := 2;
  1369.                         coefficient[2] := (max - min) / 253.0;
  1370.                         coefficient[1] := min - coefficient[2];
  1371.                         nKnownValues := 0;
  1372.                         UpdateTitleBar;
  1373.                         if macro then
  1374.                             GenerateValues;
  1375.                         ZeroClip := false;
  1376.                     end;
  1377.                     changes := true;
  1378.                     PictureType := imported;
  1379.                 end; {with}
  1380.         ImportTextFile := true;
  1381.     end;
  1382.  
  1383.  
  1384.     procedure PlotXYZ;
  1385. {Reads X-Y coordinate pairs and optional intensiy(Z) values from a}
  1386. {two or three column tab-delimited text file and plots them in the current window.}
  1387.         var
  1388.             fname, str: str255;
  1389.             RefNum, i, nColumns, nValues, index, wheight: integer;
  1390.             rLine: RealLine;
  1391.     begin
  1392.         RefNum := 0;
  1393.         if not GetTextFile(fname, RefNum) then
  1394.             exit(PlotXYZ);
  1395.         InitTextInput(fname, RefNum);
  1396.         GetLineFromText(rLine, nValues);
  1397.         nColumns := nValues;
  1398.         if not ((nColumns = 2) or (nColumns = 3)) then begin
  1399.                 PutError('File must have two or three columns.');
  1400.                 exit(PlotXYZ);
  1401.             end;
  1402.         wheight := info^.nLines;
  1403.         index := ForegroundIndex;
  1404.         repeat
  1405.             if nColumns = 3 then begin
  1406.                     index := round(rLine[3]);
  1407.                     if index > 255 then
  1408.                         index := 255;
  1409.                     if index < 0 then
  1410.                         index := 0;
  1411.                 end;
  1412.             PutPixel(round(rLine[1]), wheight - round(rLine[2] + 1), index);
  1413.             GetLineFromText(rLine, nValues);
  1414.         until nValues = 0;
  1415.         InitCursor;
  1416.     end;
  1417.  
  1418.  
  1419.  
  1420.     procedure SaveSettings;
  1421.         var
  1422.             TheInfo: FInfo;
  1423.             ByteCount: LongInt;
  1424.             f, i: integer;
  1425.             err: OSErr;
  1426.             settings: SettingsType;
  1427.             PrefsVRef: integer;
  1428.             PrefsDirID: LongInt;
  1429.             PrefsSpec: FSSpec;
  1430.             PrefsError:boolean;
  1431.     begin
  1432.         with settings, info^ do begin
  1433.                 sID := 'IMAG';
  1434.                 sVersion := version;
  1435.                 sForegroundIndex := ForegroundIndex;
  1436.                 sBackgroundIndex := BackgroundIndex;
  1437.                 sBrushHeight := BrushHeight;
  1438.                 sBrushWidth := BrushWidth;
  1439.                 sSprayCanDiameter := SprayCanDiameter;
  1440.                 sLUTMode := LUTMode;
  1441.                 sOldColorStart := 30;
  1442.                 sOldColorWidth := 10;
  1443.                 sCurrentFontID := CurrentFontID;
  1444.                 sCurrentStyle := CurrentStyle;
  1445.                 sCurrentSize := CurrentSize;
  1446.                 sTextJust := TextJust;
  1447.                 sTextBack := TextBack;
  1448.                 sNExtraColors := nExtraColors;
  1449.                 sExtraColors := ExtraColors;
  1450.                 sInvertVideo := InvertVideo;
  1451.                 sMeasurements := Measurements;
  1452.                 sInvertPlots := InvertPlots;
  1453.                 sAutoScalePlots := AutoScalePlots;
  1454.                 sLinePlot := LinePlot;
  1455.                 sDrawPlotLabels := DrawPlotLabels;
  1456.                 for i := 1 to 12 do
  1457.                     sUnused1[i] := 0;
  1458.                 sFixedSizePlot := FixedSizePlot;
  1459.                 sProfilePlotWidth := ProfilePlotWidth;
  1460.                 sProfilePlotHeight := ProfilePlotHeight;
  1461.                 sFramesToAverage := FramesToAverage;
  1462.                 sNewPicWidth := NewPicWidth;
  1463.                 sNewPicHeight := NewPicHeight;
  1464.                 sBufferSize := BufferSize;
  1465.                 sThresholdToForeground := ThresholdToForeground;
  1466.                 sNonThresholdToBackground := NonThresholdToBackground;
  1467.                 sVideoChannel := VideoChannel;
  1468.                 sWhatToImport := WhatToImport;
  1469.                 sImportCustomWidth := ImportCustomWidth;
  1470.                 sImportCustomHeight := ImportCustomHeight;
  1471.                 sImportCustomOffset := ImportCustomOffset;
  1472.                 sWandAutoMeasure := WandAutoMeasure;
  1473.                 sWandAdjustAreas := WandAdjustAreas;
  1474.                 sBinaryIterations := BinaryIterations;
  1475.                 sScaleArithmetic := ScaleArithmetic;
  1476.                 sInvertPixelValues := InvertPixelValues;
  1477.                 sInvertYCoordinates := InvertYCoordinates;
  1478.                 sFieldWidth := FieldWidth;
  1479.                 sPrecision := precision;
  1480.                 sMinParticleSize := MinParticleSize;
  1481.                 sMaxParticleSize := MaxParticleSize;
  1482.                 sIgnoreParticlesTouchingEdge := IgnoreParticlesTouchingEdge;
  1483.                 sLabelParticles := LabelParticles;
  1484.                 sOutlineParticles := OutlineParticles;
  1485.                 sIncludeHoles := IncludeHoles;
  1486.                 sOscillatingMovies := OscillatingMovies;
  1487.                 sDriverHalftoning := DriverHalftoning;
  1488.                 sMaxMeasurements := MaxMeasurements;
  1489.                 sImportCustomDepth := ImportCustomDepth;
  1490.                 sImportSwapBytes := ImportSwapBytes;
  1491.                 sImportCalibrate := ImportCalibrate;
  1492.                 sImportAutoscale := ImportAutoscale;
  1493.                 for i := 1 to 12 do
  1494.                     sUnused2[i] := 0;
  1495.                 sShowHeadings := ShowHeadings;
  1496.                 sDefaultVRefNum := 0;
  1497.                 sDefaultDirID := 0;
  1498.                 sKernelsVRefNum := 0;
  1499.                 sKernelsDirID := 0;
  1500.         {***}
  1501.                 sProfilePlotMin := ProfilePlotMin;
  1502.                 sProfilePlotMax := ProfilePlotMax;
  1503.                 sImportMin := ImportMin;
  1504.                 sImportMax := ImportMax;
  1505.                 sHighlightPixels := HighlightSaturatedPixels;
  1506.         {***}
  1507.                 sBallRadius := BallRadius;
  1508.                 sFasterBackgroundSubtraction := FasterBackgroundSubtraction;
  1509.                 sScaleConvolutions := ScaleConvolutions;
  1510.         {V1.42}
  1511.                 sBinaryCount := BinaryCount;
  1512.                 sColorTable := ColorTable;
  1513.                 sColorStart := ColorStart;
  1514.                 sColorEnd := ColorEnd;
  1515.                 sInvertedTable := InvertedColorTable;
  1516.         {V1.44}
  1517.                 sHalftoneFrequency := HalftoneFrequency;
  1518.                 sHalftoneAngle := HalftoneAngle;
  1519.                 sHalftoneDotFunction := HalftoneDotFunction;
  1520.                 sDacLow := DacLow;
  1521.                 sDacHigh := DacHigh;
  1522.                 sSyncMode := SyncMode;
  1523.                 sSwitchLUTOnSuspend := SwitchLUTOnSuspend;
  1524.                 sVideoRateAveraging := VideoRateAveraging;
  1525.                 sImportInvert := ImportInvert;
  1526.                 sTextCreator := TextCreator;
  1527.                 sMathSubGain:=MathSubGain;
  1528.                 sMathSubOffset:=round(MathSubOffset);
  1529.         {V1.60}
  1530.                 sfgScale := fgScale;
  1531.                 sUseBuiltinDigitizer := UseBuiltinDigitizer;
  1532.                 sDigitizerMode := DigitizerMode;
  1533.                 sDigitizerStandard := DigitizerStandard;
  1534.                 sLutFriendlyMode := LutFriendlyMode;
  1535.  
  1536.                 for i := 1 to 10 do
  1537.                     sUnused[i] := 0;
  1538.             end; {with}
  1539.         if System7 then begin
  1540.             {Save in Preferences folder}
  1541.             PrefsError:=true;
  1542.             err:=FindFolder(kOnSystemDisk, kPreferencesFolderType,
  1543.                         kDontCreateFolder, PrefsVRef, PrefsDirID);
  1544.             if err=noErr then
  1545.                 err:=FSMakeFSSpec(PrefsVRef, PrefsDirID, PrefsName, PrefsSpec);
  1546.             if err=noErr
  1547.                 then err:=FSpDelete(PrefsSpec);
  1548.             if (err=noErr) or (err=fnfErr) then begin
  1549.                 err:=FSpCreate(PrefsSpec, 'Imag', 'pref', smSystemScript);
  1550.                 if err=noErr then
  1551.                     err:=FSpOpenDF(PrefsSpec, fsCurPerm, f);
  1552.                 if err=noErr then
  1553.                     PrefsError:=false;
  1554.             end;
  1555.             if PrefsError then begin
  1556.                 PutError('Error saving settings file');
  1557.                 exit(SaveSettings);
  1558.             end;
  1559.         end else begin
  1560.             {Save in System folder}
  1561.             err := GetFInfo(PrefsName, SystemRefNum, TheInfo);
  1562.             if err = FNFerr then begin
  1563.                     err := create(PrefsName, SystemRefNum, 'Imag', 'pref');
  1564.                     if CheckIO(err) <> 0 then
  1565.                         exit(SaveSettings);
  1566.                 end;
  1567.             err := fsopen(PrefsName, SystemRefNum, f);
  1568.         end;
  1569.         if CheckIO(err) <> 0 then
  1570.             exit(SaveSettings);
  1571.         err := SetFPos(f, FSFromStart, 0);
  1572.         ByteCount := SizeOf(settings);
  1573.         err := fswrite(f, ByteCount, @settings);
  1574.         if CheckIO(err) <> 0 then begin
  1575.                 err := fsclose(f);
  1576.                 exit(SaveSettings)
  1577.             end;
  1578.         err := SetEof(f, ByteCount);
  1579.         err := fsclose(f);
  1580.         err := FlushVol(nil, SystemRefNum);
  1581.     end;
  1582.  
  1583.  
  1584.     procedure ExportAsText (fname: str255; RefNum: integer);
  1585.         var
  1586.             err, f, width, hloc, vloc: integer;
  1587.             TheInfo: FInfo;
  1588.             ByteCount, FileSize: LongInt;
  1589.             AutoSelectAll, InvertValues: boolean;
  1590.             tLine: LineType;
  1591.     begin
  1592.         if info = NoInfo then
  1593.             exit(ExportAsText);
  1594.         err := GetFInfo(fname, RefNum, TheInfo);
  1595.         case err of
  1596.             NoErr: 
  1597.                 if TheInfo.fdType <> 'TEXT' then begin
  1598.                         TypeMismatch(fname);
  1599.                         exit(ExportAsText)
  1600.                     end;
  1601.             FNFerr:  begin
  1602.                     err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT');
  1603.                     if CheckIO(err) <> 0 then
  1604.                         exit(ExportAsText);
  1605.                 end;
  1606.             otherwise
  1607.                 if CheckIO(err) <> 0 then
  1608.                     exit(ExportAsText)
  1609.         end;
  1610.         ShowWatch;
  1611.         err := fsopen(fname, RefNum, f);
  1612.         if CheckIO(err) <> 0 then
  1613.             exit(ExportAsText);
  1614.         AutoSelectAll := not info^.RoiShowing;
  1615.         if AutoSelectAll then
  1616.             SelectAll(true);
  1617.         if TooWide then
  1618.             exit(ExportAsText);
  1619.         FileSize := 0;
  1620.         with info^, info^.RoiRect do begin
  1621.                 InvertValues := isInvertingFunction;
  1622.                 width := right - left;
  1623.                 for vloc := top to bottom - 1 do begin
  1624.                         GetLine(left, vloc, width, tLine);
  1625.                         TextBufSize := 0;
  1626.                         for hloc := 0 to width - 1 do begin
  1627.                                 if fit = uncalibrated then
  1628.                                     PutLong(tLine[hloc], 0)
  1629.                                 else if InvertValues then
  1630.                                     PutLong(255 - tLine[hloc], 0)
  1631.                                 else
  1632.                                     PutString(StringOf(cValue[tLine[hloc]]:1:precision));
  1633.                                 if hloc <> (width - 1) then
  1634.                                     PutTab;
  1635.                             end;
  1636.                         PutChar(cr);
  1637.                         ByteCount := TextBufSize;
  1638.                         err := fswrite(f, ByteCount, ptr(TextBufP));
  1639.                         FIleSize := FileSize + ByteCount;
  1640.                         if (CheckIO(err) <> 0) or CommandPeriod then
  1641.                             leave;
  1642.                         if (vloc mod 10) = 0 then ShowAnimatedWatch;
  1643.                     end;
  1644.                 err := SetEof(f, FileSize);
  1645.                 err := fsclose(f);
  1646.                 err := FlushVol(nil, RefNum);
  1647.             end;
  1648.         if AutoSelectAll then
  1649.             KillRoi;
  1650.     end;
  1651.  
  1652.  
  1653.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  1654.         var
  1655.             err, f, i, y: integer;
  1656.             TheInfo: FInfo;
  1657.             ByteCount, FileSize: LongInt;
  1658.             InvertY: boolean;
  1659.     begin
  1660.         if not CoordinatesAvailableMsg then begin
  1661.                 exit(ExportCoordinates)
  1662.             end;
  1663.         err := GetFInfo(fname, RefNum, TheInfo);
  1664.         case err of
  1665.             NoErr: 
  1666.                 if TheInfo.fdType <> 'TEXT' then begin
  1667.                         TypeMismatch(fname);
  1668.                         exit(ExportCoordinates)
  1669.                     end;
  1670.             FNFerr:  begin
  1671.                     err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT');
  1672.                     if CheckIO(err) <> 0 then
  1673.                         exit(ExportCoordinates);
  1674.                 end;
  1675.             otherwise
  1676.                 if CheckIO(err) <> 0 then
  1677.                     exit(ExportCoordinates)
  1678.         end;
  1679.         ShowWatch;
  1680.         err := fsopen(fname, RefNum, f);
  1681.         if CheckIO(err) <> 0 then
  1682.             exit(ExportCoordinates);
  1683.         FileSize := 0;
  1684.         InvertY := InvertYCoordinates and (Info <> NoInfo);
  1685.         with info^ do
  1686.             for i := 1 to nCoordinates do begin
  1687.                     TextBufSize := 0;
  1688.                     PutLong(xCoordinates^[i] + RoiRect.left, 0);
  1689.                     PutTab;
  1690.                     y := yCoordinates^[i] + RoiRect.top;
  1691.                     if InvertY then
  1692.                         y := PicRect.bottom - y - 1;
  1693.                     PutLong(y, 0);
  1694.                     PutChar(cr);
  1695.                     ByteCount := TextBufSize;
  1696.                     err := fswrite(f, ByteCount, ptr(TextBufP));
  1697.                     FIleSize := FileSize + ByteCount;
  1698.                     if (CheckIO(err) <> 0) or CommandPeriod then
  1699.                         leave;
  1700.                 end;
  1701.         err := SetEof(f, FileSize);
  1702.         err := fsclose(f);
  1703.         err := FlushVol(nil, RefNum);
  1704.     end;
  1705.  
  1706.  
  1707.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  1708.         const
  1709.             LinesPerPass = 25;
  1710.         var
  1711.             err, f, i, first, last: integer;
  1712.             TheInfo: FInfo;
  1713.             ByteCount, FileSize: LongInt;
  1714.     begin
  1715.         err := GetFInfo(fname, RefNum, TheInfo);
  1716.         case err of
  1717.             NoErr: 
  1718.                 if TheInfo.fdType <> 'TEXT' then begin
  1719.                         TypeMismatch(fname);
  1720.                         exit(ExportMeasurements)
  1721.                     end;
  1722.             FNFerr:  begin
  1723.                     err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT');
  1724.                     if CheckIO(err) <> 0 then
  1725.                         exit(ExportMeasurements);
  1726.                 end;
  1727.             otherwise
  1728.                 if CheckIO(err) <> 0 then
  1729.                     exit(ExportMeasurements)
  1730.         end;
  1731.         ShowWatch;
  1732.         err := fsopen(fname, RefNum, f);
  1733.         if CheckIO(err) <> 0 then
  1734.             exit(ExportMeasurements);
  1735.         FileSize := 0;
  1736.         first := 1;
  1737.         last := LinesPerPass;
  1738.         repeat
  1739.             if last > mCount then
  1740.                 last := mCount;
  1741.             CopyResultsToBuffer(first, last, ShowHeadings or OptionKeyWasDown);
  1742.             ByteCount := TextBufSize;
  1743.             err := fswrite(f, ByteCount, ptr(TextBufP));
  1744.             FIleSize := FileSize + ByteCount;
  1745.             if (CheckIO(err) <> 0) or CommandPeriod or (last = mCount) then
  1746.                 leave;
  1747.             first := first + LinesPerPass;
  1748.             last := last + LinesPerPass;
  1749.         until false;
  1750.         err := SetEof(f, FileSize);
  1751.         err := fsclose(f);
  1752.         err := FlushVol(nil, RefNum);
  1753.         UnsavedResults := false;
  1754.     end;
  1755.  
  1756.  
  1757.  
  1758.     procedure Swap2Bytes (var i: integer);
  1759.         type
  1760.             atype = packed array[1..2] of char;
  1761.         var
  1762.             a: atype;
  1763.             c: char;
  1764.     begin
  1765.         a := atype(i);
  1766.         c := a[1];
  1767.         a[1] := a[2];
  1768.         a[2] := c;
  1769.         i := integer(a)
  1770.     end;
  1771.  
  1772.  
  1773.     procedure Swap4Bytes (var i: LongInt);
  1774.         var
  1775.             a: ostype;
  1776.             c: char;
  1777.     begin
  1778.         a := ostype(i);
  1779.         c := a[1];
  1780.         a[1] := a[4];
  1781.         a[4] := c;
  1782.         c := a[2];
  1783.         a[2] := a[3];
  1784.         a[3] := c;
  1785.         i := LongInt(a)
  1786.     end;
  1787.     
  1788.  
  1789.  
  1790.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  1791.         var
  1792.             TiffHeader: TiffHdr;
  1793.             ByteCount: LongInt;
  1794.             err: OSErr;
  1795.     begin
  1796.         ByteCount := 8;
  1797.         err := SetFPos(f, fsFromStart, 0);
  1798.         err := fsread(f, ByteCount, @TiffHeader);
  1799.         if CheckIO(err) <> NoErr then begin
  1800.                 OpenTiffHeader := false;
  1801.                 exit(OpenTiffHeader);
  1802.             end;
  1803.         with TiffHeader do begin
  1804.                 IntelByteOrder := ByteOrder = 'II';
  1805.                 if (ByteOrder <> 'MM') and (ByteOrder <> 'II') then begin
  1806.                         PutError('Invalid TIFF header.');
  1807.                         OpenTiffHeader := false;
  1808.                         exit(OpenTiffHeader)
  1809.                     end;
  1810.                 DirOffset := FirstIFDOffset;
  1811.                 if IntelByteOrder then
  1812.                     Swap4Bytes(DirOffset);
  1813.                 OpenTiffHeader := true;
  1814.             end;
  1815.     end;
  1816.  
  1817.  
  1818.     procedure GetTiffEntry (f: integer; var tag: integer; var N, value: LongInt);
  1819.         var
  1820.             IFDEntry: TiffEntry;
  1821.             ByteCount: LongInt;
  1822.             IntValue: integer;
  1823.             err: OSErr;
  1824.             str: str255;
  1825.     begin
  1826.         ByteCount := 12;
  1827.         err := FSRead(f, ByteCount, @IFDEntry);
  1828.         with IFDEntry do begin
  1829.                 tag := TagField;
  1830.                 N := length;
  1831.                 if IntelByteOrder then begin
  1832.                         Swap2Bytes(tag);
  1833.                         Swap2Bytes(ftype);
  1834.                         Swap4Bytes(N);
  1835.                     end;
  1836.                 value := offset;
  1837.                 if (ftype = short) and (N = 1) then begin
  1838.                         value := bsr(value, 16);
  1839.                         if IntelByteOrder then begin
  1840.                                 IntValue := value;
  1841.                                 Swap2Bytes(IntValue);
  1842.                                 value := IntValue
  1843.                             end
  1844.                     end
  1845.                 else if IntelByteOrder then
  1846.                     Swap4Bytes(value);
  1847.                 if OptionKeyWasDown then begin
  1848.                         gstr := concat(gstr, long2str(tag), '  ', long2str(ftype), '  ', long2str(N), '  ', long2str(value), crStr);
  1849.                         ShowMessage(gstr);
  1850.                     end;
  1851.             end;
  1852.     end;
  1853.  
  1854.  
  1855.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean;
  1856.         const
  1857.             NoUnit = 1;
  1858.             inch = 2;
  1859.             centimeter = 3;
  1860.         var
  1861.             ByteCount, length, ftype, N, value, BytesPerStrip, SaveFPos: LongInt;
  1862.             err: OSErr;
  1863.             nEntries, i, tag, entry: integer;
  1864.             StripOffsetsArray: array[1..2] of LongInt;
  1865.             xRes, yRes: extended;
  1866.  
  1867.         function GetResolution: extended;
  1868.             var
  1869.                 resolution: array[1..2] of LongInt;
  1870.         begin
  1871.             err := GetFPos(f, SaveFPos);
  1872.             err := SetFPos(f, fsFromStart, value);
  1873.             ByteCount := 8;
  1874.             err := fsread(f, ByteCount, @Resolution);
  1875.             if IntelByteOrder then begin
  1876.                     Swap4Bytes(Resolution[1]);
  1877.                     Swap4Bytes(Resolution[2]);
  1878.                 end;
  1879.             err := SetFPos(f, fsFromStart, SaveFPos);
  1880.             if resolution[2] <> 0 then
  1881.                 GetResolution := resolution[1] / resolution[2]
  1882.             else
  1883.                 GetResolution := 0.0;
  1884.         end;
  1885.  
  1886.     begin
  1887.         if OptionKeyWasDown then
  1888.             gstr := '';
  1889.         xRes := 0.0;
  1890.         err := SetFPos(f, fsFromStart, DirOffset);
  1891.         ByteCount := 2;
  1892.         err := FSRead(f, ByteCount, @nEntries);
  1893.         if CheckIO(err) <> NoErr then begin
  1894.                 OpenTiffDirectory := false;
  1895.                 exit(OpenTiffDirectory);
  1896.             end;
  1897.         if IntelByteOrder then
  1898.             Swap2Bytes(nEntries);
  1899.         with TiffInfo do begin
  1900.                 width := 0;
  1901.                 height := 0;
  1902.                 BitsPerPixel := 8;
  1903.                 SamplesPerPixel:=1;
  1904.                 PlanarConfig := 1;
  1905.                 OffsetToData := 0;
  1906.                 Resolution := 0.0;
  1907.                 ResUnits := tNoUnits;
  1908.                 OffsetToColorMap := 0;
  1909.                 OffsetToImageHeader := -1;
  1910.                 StripOffsetsArray[1] := 0;
  1911.                 for entry := 1 to nEntries do begin
  1912.                         GetTiffEntry(f, tag, N, value);
  1913.                         if tag = 0 then begin
  1914.                                 PutError('Invalid TIFF format.');
  1915.                                 OpenTiffDirectory := false;
  1916.                                 exit(OpenTiffDirectory)
  1917.                             end;
  1918.                         case tag of
  1919.                             ImageWidth: 
  1920.                                 width := value;
  1921.                             ImageLength: 
  1922.                                 height := value;
  1923.                             BitsPerSample:  begin
  1924.                                     if N = 1 then
  1925.                                         BitsPerPixel := value;
  1926.                                     if value = 1 then begin
  1927.                                             PutError('NIH Image cannot open 1-bit TIFF files.');
  1928.                                             OpenTiffDirectory := false;
  1929.                                             exit(OpenTiffDirectory)
  1930.                                         end;
  1931.                                     if (value = 16) and not importing then begin
  1932.                                             PutError('Use Import to open 16-bit TIFF files.');
  1933.                                             OpenTiffDirectory := false;
  1934.                                             exit(OpenTiffDirectory)
  1935.                                         end;
  1936.                                 end;
  1937.                             SamplesPerPixelTag:
  1938.                                 if (value = 1) or (value = 3) then
  1939.                                      SamplesPerPixel:=value
  1940.                                 else begin
  1941.                                     PutError('NIH Image can only open TIFF files with 1 or 3 samples per pixel.');
  1942.                                     OpenTiffDirectory := false;
  1943.                                     exit(OpenTiffDirectory)
  1944.                                 end;
  1945.                             PlanarConfigTag:
  1946.                                 PlanarConfig := value;
  1947.                             Compression: 
  1948.                                 if value <> 1 then begin
  1949.                                         PutError('NIH Image cannot open compressed TIFF files.');
  1950.                                         OpenTiffDirectory := false;
  1951.                                         exit(OpenTiffDirectory)
  1952.                                     end;
  1953.                             PhotoInterp: 
  1954.                                 ZeroIsBlack := value = 1;
  1955.                             StripOffsets: 
  1956.                                 if N = 1 then
  1957.                                     OffsetToData := value
  1958.                                 else begin
  1959.                                         err := GetFPos(f, SaveFPos);
  1960.                                         err := SetFPos(f, fsFromStart, value);
  1961.                                         ByteCount := 8;
  1962.                                         err := fsread(f, ByteCount, @StripOffsetsArray);
  1963.                                         if IntelByteOrder then begin
  1964.                                                 Swap4Bytes(StripOffsetsArray[1]);
  1965.                                                 Swap4Bytes(StripOffsetsArray[2]);
  1966.                                             end;
  1967.                                         err := SetFPos(f, fsFromStart, SaveFPos);
  1968.                                     end;
  1969.                             RowsPerStrip: 
  1970.                                 if (OffsetToData=0) and (value < height) then begin
  1971.                                         BytesPerStrip := value * width;
  1972.                                         if BitsPerPixel = 16 then
  1973.                                             BytesPerStrip := BytesPerStrip * 2
  1974.                                         else if SamplesPerPixel = 3 then
  1975.                                             BytesPerStrip := BytesPerStrip * 3;
  1976.                                         if StripOffsetsArray[1] = 0 then begin
  1977.                                                 PutError('Invalid TIFF directory.');
  1978.                                                 OpenTiffDirectory := false;
  1979.                                                 exit(OpenTiffDirectory)
  1980.                                             end;
  1981.                                         if StripOffsetsArray[2] <> (StripOffsetsArray[1] + BytesPerStrip) then begin
  1982.                                                 PutError('NIH Image cannot open TIFF files with discontiguous strips.');
  1983.                                                 OpenTiffDirectory := false;
  1984.                                                 exit(OpenTiffDirectory)
  1985.                                             end;
  1986.                                         OffsetToData := StripOffsetsArray[1];
  1987.                                     end;
  1988.                             XResolution: 
  1989.                                 XRes := GetResolution;
  1990.                             YResolution:  begin
  1991.                                     yRes := GetResolution;
  1992.                                     if (xRes = yRes) and (xRes > 0.0) then begin
  1993.                                             resolution := xRes;
  1994.                                             ResUnits := tInches;
  1995.                                         end;
  1996.                                 end;
  1997.                             ResolutionUnit: 
  1998.                                 case value of
  1999.                                     NoUnit: 
  2000.                                         ResUnits := tNoUnits;
  2001.                                     Centimeter: 
  2002.                                         ResUnits := tCentimeters;
  2003.                                     otherwise
  2004.                                 end;
  2005.                             ColorMapTag: 
  2006.                                 if N = 768 then
  2007.                                     OffsetToColorMap := value;
  2008.                             ImageHdrTag: 
  2009.                                 OffsetToImageHeader := value;
  2010.                             otherwise
  2011.                         end;
  2012.                     end; {for}
  2013.                 ByteCount := 4;
  2014.                 err := FSRead(f, ByteCount, @NextIFD);
  2015.                 if IntelByteOrder then
  2016.                     Swap4Bytes(NextIFD);
  2017.                 if OptionKeyWasDown then begin
  2018.                         gstr := concat(gstr, 'Next IFD=', long2str(NextIFD));
  2019.                         ShowMessage(gstr);
  2020.                     end;
  2021.                 if width = 0 then begin
  2022.                         PutError('Error opening TIFF directory');
  2023.                         OpenTiffDirectory := false;
  2024.                         exit(OpenTiffDirectory)
  2025.                     end;
  2026.                 if (SamplesPerPixel = 3) and (PlanarConfig <> 1) then begin
  2027.                     PutError('NIH Image cannot open RGB files with separate planes.');
  2028.                     OpenTiffDirectory := false;
  2029.                     exit(OpenTiffDirectory)
  2030.                 end;
  2031.  
  2032.             end; {with}
  2033.         OpenTiffDirectory := true;
  2034.     end;
  2035.  
  2036.  
  2037.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  2038.         var
  2039.             i: integer;
  2040.             err: OSErr;
  2041.             ColorMap: TiffColorMapType;
  2042.             ColorMapSize: LongInt;
  2043.     begin
  2044.         LoadLUT(info^.cTable);
  2045.         if ScreenDepth=8 then begin
  2046.             for i := 0 to 255 do
  2047.                 with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  2048.                     ColorMap[1, i] := red;
  2049.                     ColorMap[2, i] := green;
  2050.                     ColorMap[3, i] := blue;
  2051.                     end;
  2052.         end else begin
  2053.             for i := 0 to 255 do
  2054.                 with info^.cTable[i].rgb do begin
  2055.                     ColorMap[1, i] := red;
  2056.                     ColorMap[2, i] := green;
  2057.                     ColorMap[3, i] := blue;
  2058.                     end;
  2059.         end;
  2060.         err := SetFPos(f, FSFromStart, HeaderSize + TiffDirSize + ImageDataSize);
  2061.         ColorMapSize := SizeOf(ColorMap);
  2062.         err := fswrite(f, ColorMapSize, @ColorMap);
  2063.         if CheckIO(err) <> 0 then
  2064.             beep;
  2065.     end;
  2066.  
  2067.  
  2068.     procedure GetTiffColorMap (f: integer);
  2069.         var
  2070.             i: integer;
  2071.             ByteCount: LongInt;
  2072.             err: OSErr;
  2073.             ColorMap: TiffColorMapType;
  2074.     begin
  2075.         with info^ do begin
  2076.                 ByteCount := SizeOf(ColorMap);
  2077.                 err := SetFPos(f, fsFromStart, ColorMapOffset);
  2078.                 err := fsRead(f, ByteCount, @ColorMap);
  2079.                 if err = NoErr then begin
  2080.                         if IntelByteOrder then
  2081.                             for i := 0 to 255 do begin
  2082.                                     Swap2Bytes(ColorMap[1, i]);
  2083.                                     Swap2Bytes(ColorMap[2, i]);
  2084.                                     Swap2Bytes(ColorMap[3, i]);
  2085.                                 end;
  2086.                         for i := 0 to 255 do
  2087.                             with cTable[i].rgb do begin
  2088.                                     red := ColorMap[1, i];
  2089.                                     green := ColorMap[2, i];
  2090.                                     blue := ColorMap[3, i];
  2091.                                 end;
  2092.                         LoadLUT(cTable);
  2093.                         LUTMode := ColorLut;
  2094.                         SetupPseudocolor;
  2095.                         IdentityFunction := false;
  2096.                         if isGrayScaleLUT then begin
  2097.                                 info^.LutMode := CustomGrayScale;
  2098.                                 DrawMap;
  2099.                             end;
  2100.                     end
  2101.                 else
  2102.                     beep;
  2103.             end;{with}
  2104.     end;
  2105.  
  2106.  
  2107.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  2108.         var
  2109.             i: integer;
  2110.             err: OSErr;
  2111.             SavingStack, SavingRGBStack: boolean;
  2112.             ByteCount, width, height: LongInt;
  2113.             TiffInfo1: record
  2114.                     Header: TiffHdr;   {8}
  2115.                     nEntries: integer; {2}
  2116.                     TiffDir: array[1..9] of TiffEntry; {108}
  2117.                 end;
  2118.             ColorMapEntry: TiffEntry;  {12 (Optional)}
  2119.             TiffInfo2: record
  2120.                     ImageHdrEntry: TiffEntry;  {12}
  2121.                     NextIFD: LongInt;  {4}
  2122.                     BitsPerPixelData: array[1..3] of integer; {6} {only used for RGB files}
  2123.                     filler: array[1..TiffFillerSize] of integer; {116}
  2124.                 end;
  2125.             BitsPerSampleData: record
  2126.                 rBitsPerSample, gBitsPerSample, bBitsPerSample:integer;
  2127.             end;
  2128.     begin
  2129.         with info^ do begin
  2130.             SavingStack := false;
  2131.             SavingRGBStack := false;
  2132.             if StackInfo <> nil then
  2133.                 SavingStack := StackInfo^.nSlices > 1;
  2134.             if SavingStack then
  2135.                 if (StackInfo^.StackType = rgbStack) and (StackInfo^.nSlices = 3) then begin
  2136.                     SavingRGBStack := true;
  2137.                     ctabSize := 0;
  2138.                 end;
  2139.             if SavingSelection then begin
  2140.                     width := sPixelsPerLine;
  2141.                     height := sLines
  2142.                 end
  2143.             else begin
  2144.                     width := PixelsPerLine;
  2145.                     height := nLines
  2146.                 end;
  2147.             with TiffInfo1 do begin
  2148.                     with header do begin
  2149.                             ByteOrder := 'MM';
  2150.                             Version := 42;
  2151.                             FirstIFDOffset := 8;
  2152.                         end;
  2153.                     if ctabSize > 0 then
  2154.                         nEntries := 11
  2155.                     else
  2156.                         nEntries := 10;
  2157.                     for i := 1 to 9 do
  2158.                         with TiffDir[i] do begin
  2159.                                 ftype := 3;
  2160.                                 length := 1
  2161.                             end;
  2162.                     with TiffDir[1] do begin
  2163.                             TagField := NewSubfileType;
  2164.                             ftype := 4;
  2165.                             offset := 0;
  2166.                         end;
  2167.                     with TiffDir[2] do begin
  2168.                             TagField := ImageWidth;
  2169.                             offset := bsl(width, 16);
  2170.                         end;
  2171.                     with TiffDir[3] do begin
  2172.                             TagField := ImageLength;
  2173.                             offset := bsl(height, 16);
  2174.                         end;
  2175.                     with TiffDir[4] do begin
  2176.                             TagField := BitsPerSample;
  2177.                             if SavingRGBStack then begin
  2178.                                 ftype := 3;
  2179.                                 length := 3;
  2180.                                 offset := SizeOf(TiffInfo1) + SizeOf(TiffEntry) + SizeOf(LongInt);
  2181.                                 with TiffInfo2 do
  2182.                                     for i := 1 to 3 do
  2183.                                         BitsPerPixelData[i] := 8;
  2184.                             end else begin
  2185.                                 offset := bsl(8, 16);
  2186.                                 with TiffInfo2 do
  2187.                                     for i := 1 to 3 do
  2188.                                         BitsPerPixelData[i] := 0;
  2189.                             end;
  2190.                         end;
  2191.                     with TiffDir[5] do begin
  2192.                             TagField := PhotoInterp;
  2193.                             if SavingRGBStack then
  2194.                                 offset := bsl(2, 16)
  2195.                             else if ctabSize > 0 then
  2196.                                 offset := bsl(3, 16)
  2197.                             else
  2198.                                 offset := 0;
  2199.                         end;
  2200.                     with TiffDir[6] do begin
  2201.                             TagField := StripOffsets;
  2202.                             ftype := 4;
  2203.                             offset := TiffDirSize + HeaderSize;
  2204.                         end;
  2205.                     with TiffDir[7] do begin
  2206.                             TagField := SamplesPerPixelTag;
  2207.                             if SavingRGBStack then
  2208.                                 offset := bsl(3, 16)
  2209.                             else
  2210.                                 offset := bsl(1, 16);
  2211.                         end;
  2212.                     with TiffDir[8] do begin
  2213.                             TagField := RowsPerStrip;
  2214.                             offset := bsl(height, 16);
  2215.                         end;
  2216.                     with TiffDir[9] do begin
  2217.                             TagField := StripByteCount;
  2218.                             ftype := 4;
  2219.                             if SavingRGBStack then
  2220.                                 offset := width * height * 3
  2221.                             else
  2222.                                 offset := width * height;
  2223.                         end;
  2224.                 end;
  2225.             ByteCount := SizeOf(TiffInfo1);
  2226.             err := SetFPos(f, FSFromStart, 0);
  2227.             err := FSWrite(f, ByteCount, @TiffInfo1);
  2228.             if CheckIO(err) <> NoErr then begin
  2229.                     SaveTiffDir := err;
  2230.                     exit(SaveTiffDir);
  2231.                 end;
  2232.             if ctabSize > 0 then
  2233.                 with ColorMapEntry do begin
  2234.                         TagField := ColorMapTag;
  2235.                         ftype := 3;
  2236.                         length := 768;
  2237.                         offset := HeaderSize + TiffDirSize + ImageDataSize;
  2238.                         ByteCount := SizeOf(ColorMapEntry);
  2239.                         err := FSWrite(f, ByteCount, @ColorMapEntry);
  2240.                         if CheckIO(err) <> NoErr then begin
  2241.                                 SaveTiffDir := err;
  2242.                                 exit(SaveTiffDir);
  2243.                             end;
  2244.                     end;
  2245.             with TiffInfo2 do begin
  2246.                     with ImageHdrEntry do begin
  2247.                             TagField := ImageHdrTag;
  2248.                             ftype := 3;
  2249.                             length := 256;
  2250.                             offset := TiffDirSize;
  2251.                         end;
  2252.                     NextIFD := 0;
  2253.                     if SavingStack then
  2254.                         NextIFD := HeaderSize + TiffDirSize + ImageDataSize + ctabSize;
  2255.                     for i := 1 to TiffFillerSize do
  2256.                         filler[i] := 0;
  2257.                 end;
  2258.             end; {with info^}
  2259.         ByteCount := SizeOf(TiffInfo2);
  2260.         err := FSWrite(f, ByteCount, @TiffInfo2);
  2261.         SaveTiffDir := CheckIO(err);
  2262.     end;
  2263.  
  2264.  
  2265.     function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer;
  2266.         var
  2267.             IFD, entry: integer;
  2268.             StackIFD: StackIFDType;
  2269.             err: OSErr;
  2270.             IFDoffset, SliceOffset, ByteCount: LongInt;
  2271.     begin
  2272.         with info^, StackInfo^, StackIFD do begin
  2273.                 IFDoffset := HeaderSize + TiffDirSize + ImageDataSize + ctabSize;
  2274.                 err := SetFPos(f, FSFromStart, IFDoffset);
  2275.                 SliceOffset := HeaderSize + TiffDirSize + ImageSize;
  2276.                 for IFD := 2 to nSlices do  {IFD=Image File Directory}
  2277.                     begin
  2278.                         nEntries := 6;
  2279.                         for entry := 1 to nEntries do
  2280.                             with TiffDir[entry] do begin
  2281.                                     ftype := 3;
  2282.                                     length := 1
  2283.                                 end;
  2284.                         with TiffDir[1] do begin
  2285.                                 TagField := NewSubfileType;
  2286.                                 ftype := 4;
  2287.                                 offset := 0;
  2288.                             end;
  2289.                         with TiffDir[2] do begin
  2290.                                 TagField := ImageWidth;
  2291.                                 offset := bsl(PixelsPerLine, 16);
  2292.                             end;
  2293.                         with TiffDir[3] do begin
  2294.                                 TagField := ImageLength;
  2295.                                 offset := bsl(nLines, 16);
  2296.                             end;
  2297.                         with TiffDir[4] do begin
  2298.                                 TagField := BitsPerSample;
  2299.                                 offset := bsl(8, 16);
  2300.                             end;
  2301.                         with TiffDir[5] do begin
  2302.                                 TagField := PhotoInterp;
  2303.                                 offset := 0;
  2304.                             end;
  2305.                         with TiffDir[6] do begin
  2306.                                 TagField := StripOffsets;
  2307.                                 ftype := 4;
  2308.                                 offset := SliceOffset;
  2309.                             end;
  2310.                         SliceOffset := SliceOffset + ImageSize;
  2311.                         IFDoffset := IFDoffset + SizeOf(StackIFD);
  2312.                         if IFD <> nSlices then
  2313.                             NextIFD := IFDoffset
  2314.                         else
  2315.                             NextIFD := 0;
  2316.                         ByteCount := SizeOf(StackIFD);
  2317.                         err := fswrite(f, ByteCount, @StackIFD);
  2318.                         if err <> NoErr then begin
  2319.                                 WriteExtraTiffIFDs := err;
  2320.                                 exit(WriteExtraTiffIFDs);
  2321.                             end;
  2322.                     end; {for}
  2323.             end; {with}
  2324.         WriteExtraTiffIFDs := NoErr;
  2325.     end;
  2326.  
  2327.  
  2328.     procedure SaveLUT (fname: str255; RefNum: integer);
  2329.         var
  2330.             err: integer;
  2331.             TheInfo: FInfo;
  2332.             LUT: array[1..3] of packed array[0..255] of byte;
  2333.             i, f: integer;
  2334.             ByteCount: LongInt;
  2335.     begin
  2336.         err := GetFInfo(fname, RefNum, TheInfo);
  2337.         case err of
  2338.             NoErr: 
  2339.                 if TheInfo.fdType <> 'ICOL' then begin
  2340.                         TypeMismatch(fname);
  2341.                         exit(SaveLUT)
  2342.                     end;
  2343.             FNFerr:  begin
  2344.                     err := create(fname, RefNum, 'Imag', 'ICOL');
  2345.                     if CheckIO(err) <> 0 then
  2346.                         exit(SaveLUT);
  2347.                 end;
  2348.             otherwise
  2349.                 if CheckIO(err) <> 0 then
  2350.                     exit(SaveLUT);
  2351.         end;
  2352.         DisableDensitySlice;
  2353.         LoadLUT(Info^.cTable);
  2354.         for i := 0 to 255 do
  2355.             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  2356.                     LUT[1, i] := band(bsr(red, 8), 255);
  2357.                     LUT[2, i] := band(bsr(green, 8), 255);
  2358.                     LUT[3, i] := band(bsr(blue, 8), 255);
  2359.                 end;
  2360.         err := fsopen(fname, RefNum, f);
  2361.         if CheckIO(err) <> 0 then
  2362.             exit(SaveLUT);
  2363.         err := SetFPos(f, FSFromStart, 0);
  2364.         ByteCount := SizeOf(LUT);
  2365.         err := fswrite(f, ByteCount, @LUT);
  2366.         if CheckIO(err) <> 0 then begin
  2367.                 err := fsclose(f);
  2368.                 err := FSDelete(fname, RefNum);
  2369.                 exit(SaveLUT)
  2370.             end;
  2371.         err := SetEof(f, ByteCount);
  2372.         err := fsclose(f);
  2373.         err := GetFInfo(fname, RefNum, TheInfo);
  2374.         if TheInfo.fdCreator <> 'Imag' then begin
  2375.                 TheInfo.fdCreator := 'Imag';
  2376.                 err := SetFInfo(fname, RefNum, TheInfo);
  2377.             end;
  2378.         err := FlushVol(nil, RefNum);
  2379.     end;
  2380.  
  2381.  
  2382.     procedure SaveColorTable (fname: str255; RefNum: integer);
  2383.         var
  2384.             err: integer;
  2385.             TheInfo: FInfo;
  2386.             i, f: integer;
  2387.             ByteCount: LongInt;
  2388.             hdr: PaletteHeader;
  2389.     begin
  2390.         with info^ do
  2391.             err := GetFInfo(fname, RefNum, TheInfo);
  2392.         case err of
  2393.             NoErr: 
  2394.                 if TheInfo.fdType <> 'ICOL' then begin
  2395.                         TypeMismatch(fname);
  2396.                         exit(SaveColorTable)
  2397.                     end;
  2398.             FNFerr:  begin
  2399.                     err := create(fname, RefNum, 'Imag', 'ICOL');
  2400.                     if CheckIO(err) <> 0 then
  2401.                         exit(SaveColorTable);
  2402.                 end;
  2403.             otherwise
  2404.                 if CheckIO(err) <> 0 then
  2405.                     exit(SaveColorTable);
  2406.         end;
  2407.         with info^ do begin
  2408.                 InitPaletteHeader(hdr);
  2409.                 err := fsopen(fname, RefNum, f);
  2410.                 if CheckIO(err) <> 0 then
  2411.                     exit(SaveColorTable);
  2412.                 err := SetFPos(f, FSFromStart, 0);
  2413.                 ByteCount := SizeOf(PaletteHeader);
  2414.                 if ByteCount <> 32 then
  2415.                     PutError('Palette header size <> 32.');
  2416.                 err := fswrite(f, ByteCount, @hdr);
  2417.                 ByteCount := nColors;
  2418.                 err := fswrite(f, ByteCount, @redLUT);
  2419.                 ByteCount := nColors;
  2420.                 err := fswrite(f, ByteCount, @greenLUT);
  2421.                 ByteCount := nColors;
  2422.                 err := fswrite(f, ByteCount, @blueLUT);
  2423.                 if CheckIO(err) <> 0 then begin
  2424.                         err := fsclose(f);
  2425.                         err := FSDelete(fname, RefNum);
  2426.                         exit(SaveColorTable)
  2427.                     end;
  2428.                 err := SetEOF(f, SizeOf(PaletteHeader) + 3 * nColors);
  2429.                 err := fsclose(f);
  2430.                 err := GetFInfo(fname, RefNum, TheInfo);
  2431.                 if TheInfo.fdCreator <> 'Imag' then begin
  2432.                         TheInfo.fdCreator := 'Imag';
  2433.                         err := SetFInfo(fname, RefNum, TheInfo);
  2434.                     end;
  2435.                 err := FlushVol(nil, RefNum);
  2436.             end; {with info^}
  2437.     end;
  2438.  
  2439.  
  2440.     procedure SaveOutline (fname: str255; RefNum: integer);
  2441.         var
  2442.             err: integer;
  2443.             TheInfo: FInfo;
  2444.             i, f: integer;
  2445.             ByteCount, DataSize: LongInt;
  2446.             hdr: RoiHeader;
  2447.             SaveCoordinates: boolean;
  2448.             dX1, dY1, dX2, dY2: extended;
  2449.     begin
  2450.         with info^ do begin
  2451.                 if not RoiShowing then begin
  2452.                         PutError('No outline available to save.');
  2453.                         exit(SaveOutline);
  2454.                     end;
  2455.                 if (RoiType = FreeLineRoi) or (RoiType = SegLineRoi) then begin
  2456.                         PutError('Freehand and segmented line selections cannot be saved.');
  2457.                         exit(SaveOutline);
  2458.                     end;
  2459.                 SaveCoordinates := (RoiType = PolygonRoi) or (RoiType = FreehandRoi) or (RoiType = TracedRoi);
  2460.                 if SaveCoordinates then
  2461.                     if not CoordinatesAvailableMsg then begin
  2462.                             exit(SaveOutline);
  2463.                         end;
  2464.                 err := GetFInfo(fname, RefNum, TheInfo);
  2465.                 case err of
  2466.                     NoErr: 
  2467.                         if TheInfo.fdType <> 'Iout' then begin
  2468.                                 TypeMismatch(fname);
  2469.                                 exit(SaveOutline)
  2470.                             end;
  2471.                     FNFerr:  begin
  2472.                             err := create(fname, RefNum, 'Imag', 'Iout');
  2473.                             if CheckIO(err) <> 0 then
  2474.                                 exit(SaveOutline);
  2475.                         end;
  2476.                     otherwise
  2477.                         if CheckIO(err) <> 0 then
  2478.                             exit(SaveOutline);
  2479.                 end;
  2480.                 with hdr do begin
  2481.                         rID := 'Iout';
  2482.                         rVersion := version;
  2483.                         rRoiType := RoiType;
  2484.                         rRoiRect := RoiRect;
  2485.                         rNCoordinates := nCoordinates;
  2486.                         GetLoi(dX1, dY1, dX2, dY2);
  2487.                         rX1:=dX1; rY1:=dY1; rX2:=dX2; rY2:=dY2;
  2488.                         rLineWidth := LineWidth;
  2489.                         for i := 1 to 14 do
  2490.                             rUnused[i] := 0;
  2491.                     end;
  2492.                 err := fsopen(fname, RefNum, f);
  2493.                 if CheckIO(err) <> 0 then
  2494.                     exit(SaveOutline);
  2495.                 err := SetFPos(f, FSFromStart, 0);
  2496.                 ByteCount := SizeOf(RoiHeader);
  2497.                 if ByteCount <> 64 then
  2498.                     PutError('Roi header size <> 32.');
  2499.                 err := fswrite(f, ByteCount, @hdr);
  2500.                 if SaveCoordinates then begin
  2501.                         ByteCount := nCoordinates * 2;
  2502.                         err := fswrite(f, ByteCount, ptr(xCoordinates));
  2503.                         ByteCount := nCoordinates * 2;
  2504.                         err := fswrite(f, ByteCount, ptr(yCoordinates));
  2505.                         DataSize := nCoordinates * 4;
  2506.                     end
  2507.                 else
  2508.                     DataSize := 0;
  2509.                 if CheckIO(err) <> 0 then begin
  2510.                         err := fsclose(f);
  2511.                         err := FSDelete(fname, RefNum);
  2512.                         exit(SaveOutline)
  2513.                     end;
  2514.                 err := SetEOF(f, SizeOf(RoiHeader) + DataSize);
  2515.                 err := fsclose(f);
  2516.                 err := GetFInfo(fname, RefNum, TheInfo);
  2517.                 if TheInfo.fdCreator <> 'Imag' then begin
  2518.                         TheInfo.fdCreator := 'Imag';
  2519.                         err := SetFInfo(fname, RefNum, TheInfo);
  2520.                     end;
  2521.                 err := FlushVol(nil, RefNum);
  2522.             end; {with info^}
  2523.     end;
  2524.  
  2525.  
  2526.     procedure OpenOutline (fname: str255; RefNum: integer);
  2527.         var
  2528.             err, f, i: integer;
  2529.             count: LongInt;
  2530.             hdr: RoiHeader;
  2531.             okay: boolean;
  2532.     begin
  2533.         if Info = NoInfo then begin
  2534.                 if (NewPicWidth * NewPicHeight) <= UndoBufSize then begin
  2535.                         if not NewPicWindow('Untitled', NewPicWidth, NewPicHeight) then
  2536.                             exit(OpenOutline)
  2537.                     end
  2538.                 else begin
  2539.                         beep;
  2540.                         exit(OpenOutline)
  2541.                     end;
  2542.             end;
  2543.         KillRoi;
  2544.         err := fsopen(fname, RefNum, f);
  2545.         with info^, hdr do begin
  2546.                 count := SizeOf(RoiHeader);
  2547.                 err := fsread(f, count, @hdr);
  2548.                 if rID <> 'Iout' then begin
  2549.                         err := fsclose(f);
  2550.                         PutError('File is corrupted.');
  2551.                         exit(OpenOutline)
  2552.                     end;
  2553.                 if (rRoiRect.right > PicRect.right) or (rRoiRect.bottom > PicRect.bottom) then begin
  2554.                         err := fsclose(f);
  2555.                         PutError('Image is too small for the outline.');
  2556.                         exit(OpenOutline)
  2557.                     end;
  2558.                 case rRoiType of
  2559.                     LineRoi:  begin
  2560.                             LX1 := rX1;
  2561.                             LY1 := rY1;
  2562.                             LX2 := rX2;
  2563.                             LY2 := rY2;
  2564.                             RoiType := LineRoi;
  2565.                             MakeRegion;
  2566.                             SetupUndo;
  2567.                             RoiShowing := true;
  2568.                         end;
  2569.                     RectRoi, OvalRoi:  begin
  2570.                             RoiType := rRoiType;
  2571.                             RoiRect := rRoiRect;
  2572.                             MakeRegion;
  2573.                             SetupUndo;
  2574.                             RoiShowing := true;
  2575.                         end;
  2576.                     PolygonRoi, FreehandRoi, TracedRoi: 
  2577.                         if (rNCoordinates > 2) and (rNCoordinates <= MaxCoordinates) then begin
  2578.                                 count := rNCoordinates * 2;
  2579.                                 err := fsread(f, count, ptr(xCoordinates));
  2580.                                 count := rNCoordinates * 2;
  2581.                                 err := fsread(f, count, ptr(yCoordinates));
  2582.                                 if CheckIO(err) = 0 then begin
  2583.                                         nCoordinates := rNCoordinates;
  2584.                                         SelectionMode := NewSelection;
  2585.                                         if rVersion >= 148 then
  2586.                                             for i := 1 to nCoordinates do
  2587.                                                 with rRoiRect do begin
  2588.                                                         xCoordinates^[i] := xCoordinates^[i] + left;
  2589.                                                         yCoordinates^[i] := yCoordinates^[i] + top;
  2590.                                                     end;
  2591.                                         MakeOutline(rRoiType);
  2592.                                         SetupUndo;
  2593.                                     end;
  2594.                             end;
  2595.                 end;
  2596.             end;
  2597.         err := fsclose(f);
  2598.     end;
  2599.  
  2600.  
  2601.     function GetTIFFParameters (name: str255; RefNum: integer; var HasColorMap: boolean): boolean;
  2602.         var
  2603.             err: OSErr;
  2604.             f: integer;
  2605.             DirOffset: LongInt;
  2606.             TiffInfo: TiffInfoRec;
  2607.     begin
  2608.         GetTIFFParameters := false;
  2609.         HasColorMap := false;
  2610.         err := fsopen(name, RefNum, f);
  2611.         if err <> NoErr then
  2612.             exit(GetTIFFParameters);
  2613.         if not OpenTiffHeader(f, DirOffset) then begin
  2614.                 err := fsclose(f);
  2615.                 exit(GetTIFFParameters)
  2616.             end;
  2617.         if not OpenTiffDirectory(f, DirOffset, TiffInfo, true) then begin
  2618.                 err := fsclose(f);
  2619.                 exit(GetTIFFParameters)
  2620.             end;
  2621.         with TiffInfo do begin
  2622.                 ImportCustomWidth := width;
  2623.                 ImportCustomHeight := height;
  2624.                 ImportCustomOffset := OffsetToData;
  2625.                 ImportAutoScale:=true;
  2626.                 if BitsPerPixel = 16 then begin
  2627.                         ImportCustomDepth := SixteenBitsUnsigned;
  2628.                         ImportSwapBytes := IntelByteOrder;
  2629.                     end
  2630.                 else begin
  2631.                         ImportCustomDepth := EightBits;
  2632.                         ImportInvert := ZeroIsBlack;
  2633.                     end;
  2634.                 HasColorMap := OffsetToColorMap > 0;
  2635.             end;
  2636.         if ImportCustomDepth = EightBits then begin
  2637.             WhatToImport := ImportTiff;
  2638.             WhatToOpen := OpenTiff
  2639.         end else begin
  2640.             WhatToImport := ImportCustom;
  2641.             WhatToOpen := OpenCustom
  2642.         end;
  2643.         err := fsclose(f);
  2644.         GetTIFFParameters := true;
  2645.     end;
  2646.  
  2647.  
  2648.     procedure GetXUnits (UnitsKind: UnitsType);
  2649.     begin
  2650.         with info^ do
  2651.             case UnitsKind of
  2652.                 Nanometers: 
  2653.                     xUnit := 'nm';
  2654.                 Micrometers: 
  2655.                     xUnit := 'µm';
  2656.                 Millimeters: 
  2657.                     xUnit := 'mm';
  2658.                 Centimeters: 
  2659.                     xUnit := 'cm';
  2660.                 Meters: 
  2661.                     xUnit := 'meter';
  2662.                 Kilometers: 
  2663.                     xUnit := 'km';
  2664.                 Inches: 
  2665.                     xUnit := 'inch';
  2666.                 feet: 
  2667.                     xUnit := 'ft';
  2668.                 Miles: 
  2669.                     xUnit := 'mile';
  2670.                 Pixels: 
  2671.                     xUnit := 'pixel';
  2672.                 otherwise
  2673.                     ;
  2674.             end;
  2675.     end;
  2676.  
  2677.  
  2678.     procedure GetUnitsKInd (var UnitsKind: UnitsType; var UnitsPerCM: extended);
  2679.     begin
  2680.         with info^ do begin
  2681.                 if xunit = 'nm' then begin
  2682.                         UnitsKind := Nanometers;
  2683.                         UnitsPerCm := 10000000.0;
  2684.                     end
  2685.                 else if xUnit = 'µm' then begin
  2686.                         UnitsKind := Micrometers;
  2687.                         UnitsPerCm := 10000.0;
  2688.                     end
  2689.                 else if xUnit = 'mm' then begin
  2690.                         UnitsKind := Millimeters;
  2691.                         UnitsPerCm := 10.0;
  2692.                     end
  2693.                 else if xUnit = 'cm' then begin
  2694.                         UnitsKind := Centimeters;
  2695.                         UnitsPerCm := 1.0;
  2696.                     end
  2697.                 else if xUnit = 'meter' then begin
  2698.                         UnitsKind := Meters;
  2699.                         UnitsPerCm := 0.01;
  2700.                     end
  2701.                 else if xUnit = 'km' then begin
  2702.                         UnitsKind := Kilometers;
  2703.                         UnitsPerCm := 0.00001;
  2704.                     end
  2705.                 else if xUnit = 'inch' then begin
  2706.                         UnitsKind := Inches;
  2707.                         UnitsPerCm := 0.3937;
  2708.                     end
  2709.                 else if xUnit = 'ft' then begin
  2710.                         UnitsKind := feet;
  2711.                         UnitsPerCm := 0.0328083;
  2712.                     end
  2713.                 else if xUnit = 'mile' then begin
  2714.                         UnitsKind := Miles;
  2715.                         UnitsPerCm := 0.000006213;
  2716.                     end
  2717.                 else if xUnit = 'pixel' then begin
  2718.                         UnitsKind := pixels;
  2719.                         UnitsPerCm := 0.0;
  2720.                         SpatiallyCalibrated := false;
  2721.                     end
  2722.                 else begin
  2723.                         UnitsKind := OtherUnits;
  2724.                         UnitsPerCm := 0.0;
  2725.                     end;
  2726.             end;
  2727.     end;
  2728.  
  2729.  
  2730. end.